From 69d872953e314b4bc008b304a5aa8f7e510b6a86 Mon Sep 17 00:00:00 2001 From: Paula Date: Sun, 16 May 2021 18:04:21 -0400 Subject: [PATCH 01/46] Made a Manual moves check button on the GU and currently making a window appear once it is toggled --- vpr/main.ui | 26 +++++++++++++++++++++++--- vpr/src/draw/buttons.cpp | 2 +- vpr/src/draw/draw.cpp | 14 ++++++++++++++ vpr/src/place/move_utils.h | 17 +++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/vpr/main.ui b/vpr/main.ui index 5b63af252a3..b6cc2e41fd2 100644 --- a/vpr/main.ui +++ b/vpr/main.ui @@ -229,8 +229,28 @@ 1 1 - - + + + + + Manual Move True + True + False + 0 + False + True + + + 0 + 3 + 1 + 1 + + + + + + Clip Routing Util True @@ -254,7 +274,7 @@ 1 1 - + diff --git a/vpr/src/draw/buttons.cpp b/vpr/src/draw/buttons.cpp index 9773463b420..a6bc64829f7 100644 --- a/vpr/src/draw/buttons.cpp +++ b/vpr/src/draw/buttons.cpp @@ -22,7 +22,7 @@ //location of spin buttons, combo boxes, and labels on grid gint box_width = 1; -gint box_height = 1; +gint box_height = 0.5; gint label_left_start_col = 0; gint box_left_start_col = 0; gint button_row = 2; // 2 is the row num of the window button in main.ui, add buttons starting from this row diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 7137df62b8f..18ce8d770a0 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -162,6 +162,7 @@ static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*d static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); static void run_graphics_commands(std::string commands); +//Manual moves generator functions void manual_move_generator_window(); void move_generator_button_callback(GtkWidget* /*widget*/, GtkWidget* grid); @@ -172,6 +173,15 @@ constexpr float SB_EDGE_TURN_ARROW_POSITION = 0.2; constexpr float SB_EDGE_STRAIGHT_ARROW_POSITION = 0.95; constexpr float EMPTY_BLOCK_LIGHTEN_FACTOR = 0.20; +//struct that contains information about manual moves for drawing +struct ManualMovesGlobal { + manual_move_info draw_manual_move_info; + GtkWidget* manual_move_window; + //Considering adding more informtion if needed***** +}; + + + //Kelly's maximum contrast colors are selected to be easily distinguishable as described in: // Kenneth Kelly, "Twenty-Two Colors of Maximum Contrast", Color Eng. 3(6), 1943 //We use these to highlight a relatively small number of things (e.g. stages in a critical path, @@ -4115,6 +4125,10 @@ static void setup_default_ezgl_callbacks(ezgl::application* app) { // Connect Debug Button GObject* debugger = app->get_object("debugButton"); g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); + + //Manual Moves Button + GObject* manual_moves = app->get_object("manualMove"); + g_signal_connect(manual_moves, "toggled", G_CALLBACK(move_generator_button_callback), app); } // Callback function for Block Outline checkbox diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index 93e229615b7..8ac01cf1e4c 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -170,4 +170,21 @@ void compressed_grid_to_loc(t_logical_block_type_ptr blk_type, int cx, int cy, t */ bool find_compatible_compressed_loc_in_range(t_logical_block_type_ptr type, int min_cx, int max_cx, int min_cy, int max_cy, int delta_cx, int cx_from, int cy_from, int& cx_to, int& cy_to, bool is_median); +//Manual moves struct: Contains the values needed for a manual move (e.g. block_ID, block_name, x_position, y_position, cost, timing, if input is valid, and if the move is acepted. +struct manual_move_info { + int block_id = -1; + std::string block_name = NULL; + int x_position = -1; + int y_position = -1; + float delta_cost = 0; + float delta_timing = 0; + bool valid_input = true; + e_move_result user_move_outcome = ABORTED; + e_move_result placer_move_outcome = ABORTED; + //considering adding more attributes needed for manual moves****** +}; + + + + #endif From 96f214d5d3ad7d646672a0bc91db0a5b53066dc4 Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 21 May 2021 12:16:20 -0400 Subject: [PATCH 02/46] Implemented the user input window, the toggle button in the UI and evaluated if the input is valid by checking location contraints and if the block is found --- vpr/main.ui | 18 ++++++++++++++++++ vpr/src/draw/draw.cpp | 30 ++++++++++++++++++++++++------ vpr/src/draw/draw.h | 1 + vpr/src/place/move_utils.h | 1 + 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/vpr/main.ui b/vpr/main.ui index 5b63af252a3..4540cc6c1f4 100644 --- a/vpr/main.ui +++ b/vpr/main.ui @@ -247,6 +247,24 @@ 1 + + + + Manual Move + True + True + True + 0 + True + + + 0 + 3 + 1 + 1 + + + 4 diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 7137df62b8f..1544d6563eb 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -160,10 +160,10 @@ static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, gpointe static void set_block_outline(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); +static void manual_moves_callback(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/, ezgl::application* app); static void run_graphics_commands(std::string commands); -void manual_move_generator_window(); -void move_generator_button_callback(GtkWidget* /*widget*/, GtkWidget* grid); +bool get_manual_move_flag(); /************************** File Scope Variables ****************************/ @@ -4062,11 +4062,12 @@ static void highlight_blocks(double x, double y) { /* Highlight block and fan-in/fan-outs. */ draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index), cluster_ctx.clb_nlist.block_name(clb_index).c_str(), place_ctx.block_locs[clb_index].loc.x, place_ctx.block_locs[clb_index].loc.y); - } - + } + application.update_message(msg); application.refresh_drawing(); + } void set_net_alpha_value(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { std::string fa(gtk_entry_get_text((GtkEntry*)widget)); @@ -4115,6 +4116,18 @@ static void setup_default_ezgl_callbacks(ezgl::application* app) { // Connect Debug Button GObject* debugger = app->get_object("debugButton"); g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); + + // Connect Manual Moves checkbox + GObject* manual_moves = app->get_object("manualMove"); + g_signal_connect(manual_moves, "toggled", G_CALLBACK(manual_moves_callback), app); +} + +//Toggle function for manual moves +static void manual_moves_callback(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/, ezgl::application* app) { + if(gtk_toggle_button_get_active((GtkToggleButton*)widget)) { + //std::cout << "Checkbox was pressed" << std::endl; + draw_manual_moves_window(app); + } } // Callback function for Block Outline checkbox @@ -4136,8 +4149,8 @@ static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*d t_draw_state* draw_state = get_draw_state_vars(); // assign corresponding bool value to draw_state->draw_block_text - if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) - draw_state->draw_block_text = true; + if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) + draw_state->draw_block_text = true; else draw_state->draw_block_text = false; @@ -4177,6 +4190,11 @@ void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data application.refresh_drawing(); } +bool get_manual_move_flag() { + GObject* manual_moves = application.get_object("manualMove"); + return gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); +} + static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { t_draw_state* draw_state = get_draw_state_vars(); diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index 8e3cacd9dd0..ebe90441955 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -14,6 +14,7 @@ # include "draw_color.h" # include "search_bar.h" # include "draw_debug.h" +# include "manual_moves.h" extern ezgl::application::settings settings; extern ezgl::application application; diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index 93e229615b7..eeef5949a58 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -43,6 +43,7 @@ struct t_edge_cost { float criticality; //the timing criticality of the net terminal that caused this edge }; + /** * @brief Stores the bounding box of a net in terms of the minimum and * maximum coordinates of the blocks forming the net, clipped to From 3a78b83f09a617f2f173bf82663c252c491f979f Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 4 Jun 2021 10:43:37 -0400 Subject: [PATCH 03/46] Adding the manual moves functions --- vpr/src/draw/draw.cpp | 29 ++- vpr/src/draw/draw.h | 3 + vpr/src/draw/manual_moves.cpp | 344 ++++++++++++++++++++++++++++ vpr/src/draw/manual_moves.h | 69 ++++++ vpr/src/place/move_utils.cpp | 5 + vpr/src/place/move_utils.h | 2 + vpr/src/place/place.cpp | 88 ++++++- vpr/src/place/place.h | 4 + vpr/src/place/placer_breakpoint.cpp | 1 + 9 files changed, 530 insertions(+), 15 deletions(-) create mode 100644 vpr/src/draw/manual_moves.cpp create mode 100644 vpr/src/draw/manual_moves.h diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 1544d6563eb..d3288816ad0 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -47,6 +47,7 @@ #include "physical_types.h" #include "route_common.h" #include "breakpoint.h" +#include "manual_moves.h" #include "move_utils.h" @@ -163,8 +164,6 @@ static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer static void manual_moves_callback(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/, ezgl::application* app); static void run_graphics_commands(std::string commands); -bool get_manual_move_flag(); - /************************** File Scope Variables ****************************/ //The arrow head position for turning/straight-thru connections in a switch box @@ -209,6 +208,7 @@ ezgl::application::settings settings("/ezgl/main.ui", setup_default_ezgl_callbacks); ezgl::application application(settings); +//bool mm_window = false; bool window_mode = false; bool window_point_1_collected = false; ezgl::point2d point_1(0, 0); @@ -4063,9 +4063,16 @@ static void highlight_blocks(double x, double y) { draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index), cluster_ctx.clb_nlist.block_name(clb_index).c_str(), place_ctx.block_locs[clb_index].loc.x, place_ctx.block_locs[clb_index].loc.y); } - - application.update_message(msg); + //If manual moves is activated, then user can select block from the grid. + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + if(get_manual_move_flag()) { + if(!manual_move_global->mm_window_is_open) { + draw_manual_moves_window(std::to_string(size_t(clb_index))); + } + } + + application.update_message(msg); application.refresh_drawing(); } @@ -4118,17 +4125,17 @@ static void setup_default_ezgl_callbacks(ezgl::application* app) { g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); // Connect Manual Moves checkbox - GObject* manual_moves = app->get_object("manualMove"); - g_signal_connect(manual_moves, "toggled", G_CALLBACK(manual_moves_callback), app); + //GObject* manual_moves = app->get_object("manualMove"); + //g_signal_connect(manual_moves, "toggled", G_CALLBACK(manual_moves_callback), app); } //Toggle function for manual moves -static void manual_moves_callback(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/, ezgl::application* app) { - if(gtk_toggle_button_get_active((GtkToggleButton*)widget)) { +//static void manual_moves_callback(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/, ezgl::application* app) { + /* if(gtk_toggle_button_get_active((GtkToggleButton*)widget)) { //std::cout << "Checkbox was pressed" << std::endl; - draw_manual_moves_window(app); + //draw_manual_moves_window(""); } -} +}*/ // Callback function for Block Outline checkbox static void set_block_outline(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { @@ -4190,7 +4197,7 @@ void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data application.refresh_drawing(); } -bool get_manual_move_flag() { +bool get_manual_move_flag() { GObject* manual_moves = application.get_object("manualMove"); return gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); } diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index ebe90441955..c0abc79a354 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -103,6 +103,9 @@ void clear_colored_locations(); // otherwise, the function returns false (the location isn't among the highlighted locations) bool highlight_loc_with_specific_color(int x, int y, ezgl::color& loc_color); +//Returns if the option for manual moves has been activated or not. Useful for place.cpp file. +bool get_manual_move_flag(); + #endif /* NO_GRAPHICS */ #endif /* DRAW_H */ diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp new file mode 100644 index 00000000000..311619585cf --- /dev/null +++ b/vpr/src/draw/manual_moves.cpp @@ -0,0 +1,344 @@ +#include "manual_moves.h" +#include "move_utils.h" +#include "globals.h" +//#include "draw_debug.h" +#include "draw.h" +#include "move_generator.h" + +#ifndef NO_GRAPHICS + +//Global Variables +ManualMovesGlobals manual_moves_global; + +void draw_manual_moves_window(std::string block_id) { + + std::cout << "Entered function in different file" << std::endl; + + if(!manual_moves_global.mm_window_is_open) { + manual_moves_global.mm_window_is_open = true; + + //Window settings + manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position((GtkWindow*)manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*)manual_moves_global.manual_move_window, "Manual Moves Generator"); + gtk_widget_set_name(manual_moves_global.manual_move_window, "manualMovesWindow"); + + + GtkWidget* grid = gtk_grid_new(); + GtkWidget* block_entry = gtk_entry_new(); + gtk_entry_set_text((GtkEntry*)block_entry, block_id.c_str()); + GtkWidget* x_position_entry = gtk_entry_new(); + GtkWidget* y_position_entry = gtk_entry_new(); + GtkWidget* subtile_position_entry = gtk_entry_new(); + GtkWidget* block_label = gtk_label_new("Block ID/Block Name:"); + GtkWidget* to_label = gtk_label_new("To Location:"); + GtkWidget* x = gtk_label_new("x:"); + GtkWidget* y = gtk_label_new("y:"); + GtkWidget* subtile = gtk_label_new("Subtile:"); + + GtkWidget* calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); + std::cout << "In draw_mm_window: " << block_id << std::endl; + + //Add all to grid + gtk_grid_attach((GtkGrid*)grid, block_label, 0, 0, 1, 1); + gtk_grid_attach((GtkGrid*)grid, block_entry, 0, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, to_label, 2, 0, 1, 1); + gtk_grid_attach((GtkGrid*)grid, x, 1, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, x_position_entry, 2, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, y, 1, 2, 1, 1); + gtk_grid_attach((GtkGrid*)grid, y_position_entry, 2, 2, 1, 1); + gtk_grid_attach((GtkGrid*)grid, subtile, 1, 3, 1, 1); + gtk_grid_attach((GtkGrid*)grid, subtile_position_entry, 2, 3, 1, 1); + gtk_grid_attach((GtkGrid*)grid, calculate_cost_button, 0, 4, 3, 1); //spans three columns + + //Set margins + gtk_widget_set_margin_bottom(grid, 20); + gtk_widget_set_margin_top(grid, 20); + gtk_widget_set_margin_start(grid, 20); + gtk_widget_set_margin_end(grid, 20); + gtk_widget_set_margin_bottom(block_label, 5); + gtk_widget_set_margin_bottom(to_label, 5); + gtk_widget_set_margin_top(calculate_cost_button, 15); + gtk_widget_set_margin_start(x, 13); + gtk_widget_set_margin_start(y, 13); + gtk_widget_set_halign(calculate_cost_button, GTK_ALIGN_CENTER); + + g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + + //connect signals + g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); + + + gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); + gtk_widget_show_all(manual_moves_global.manual_move_window); + } +} + +void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { + + int block_id; + int x_location; + int y_location; + int subtile_location; + bool valid_input = true; + auto& cluster_ctx = g_vpr_ctx.clustering(); + + //Getting entry values + GtkWidget* block_entry = gtk_grid_get_child_at((GtkGrid*)grid, 0, 1); + std::string block_id_string = gtk_entry_get_text((GtkEntry*)block_entry); + + if(string_is_a_number(block_id_string)) { //for block ID + block_id = std::atoi(block_id_string.c_str()); + } + else { //for block name + block_id = size_t(cluster_ctx.clb_nlist.find_block(gtk_entry_get_text((GtkEntry*)block_entry))); + } + //if the block is not found + if((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id))) || (cluster_ctx.clb_nlist.find_blockblock_id) == BlockId::INVALID)) { + invalid_breakpoint_entry_window("Invalid block ID/Name"); + valid_input = false; + } + + GtkWidget* x_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 1); + GtkWidget* y_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 2); + GtkWidget* subtile_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 3); + + x_location = std::atoi(gtk_entry_get_text((GtkEntry*)x_position_entry)); + y_location = std::atoi(gtk_entry_get_text((GtkEntry*)y_position_entry)); + subtile_location = std::atoi(gtk_entry_get_text((GtkEntry*)subtile_position_entry)); + + + //Check validity of the location (i.e. within bounds) + auto& device_ctx = g_vpr_ctx.device(); + if(x_location < 0 || x_location > int(device_ctx.grid.width())) { + invalid_breakpoint_entry_window("x value is out of bounds"); + valid_input = false; + } + if(y_location < 0 || y_location > int(device_ctx.grid.height())) { + invalid_breakpoint_entry_window("y value is out of bounds"); + valid_input = false; + } + + //Checking the subtile validity + if(subtile_location < 0 || subtile_location > int(device_ctx.grid[x_location][y_location].type->capacity)) { + invalid_breakpoint_entry_window("Invalid subtile value"); + valid_input = false; + } + + //Checks if all fields from the user input window are complete. + if(std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { + invalid_breakpoint_entry_window("Not all fields are complete"); + valid_input = false; + } + + if(valid_input) { + + manual_moves_global.manual_move_info.valid_input = true; + manual_moves_global.manual_move_info.blockID = block_id; + manual_moves_global.manual_move_info.x_pos = x_location; + manual_moves_global.manual_move_info.y_pos = y_location; + manual_moves_global.manual_move_info.subtile = subtile_location; + + std::cout << "valid input: " << manual_moves_global.manual_move_info.valid_input << std::endl; + std::cout << "block id: " << manual_moves_global.manual_move_info.blockID << std::endl; + std::cout << "x location: " << manual_moves_global.manual_move_info.x_pos << std::endl; + std::cout << "y location: " << manual_moves_global.manual_move_info.y_pos << std::endl; + std::cout << "subtile: " << manual_moves_global.manual_move_info.subtile << std::endl; + + manual_moves_global.manual_move_info.to_location = t_pl_loc(manual_moves_global.manual_move_info.x_pos, manual_moves_global.manual_move_info.y_pos, manual_moves_global.manual_move_info.subtile); + //std::cout << "To location x: " << manual_moves_global.manual_move_info.to_location.x << std::endl; + + //Highlighting the block + ClusterBlockId clb_index = ClusterBlockId(block_id); + + //Unselects all blocks first + deselect_all(); + + //Highlight block requested by user + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); + application.refresh_drawing(); + + } + else { + manual_moves_global.manual_move_info.valid_input = false; + } + +} + +bool string_is_a_number(std::string block_id) { + for(size_t i = 0; i < block_id.size(); i++) { + //Returns 0 if the string does not have characters from 0-9 + if(isdigit(block_id[i]) == 0) { + return false; + } + } + return true; +} + +ManualMovesInfo* get_manual_move_info() { + //returning the address to manual move info + return &manual_moves_global.manual_move_info; +} + +ManualMovesGlobals* get_manual_moves_global() { + return &manual_moves_global; +} + +//Manual Move Generator function +e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/) { + + std::cout << "In propose move function" << std::endl; + + int block_id = manual_moves_global.manual_move_info.blockID; + t_pl_loc to = manual_moves_global.manual_move_info.to_location; + + //std::cout << "In propose move function: " << to.x << ", " << to.y << ", " << to.sub_tile << std::endl; + + ClusterBlockId b_from = ClusterBlockId(block_id); + + //Checking if the block was found + if(!b_from) { + return e_create_move::ABORT; //No movable block was found + } + + auto& place_ctx = g_vpr_ctx.placement(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& device_ctx = g_vpr_ctx.device(); + + //Gets the current location of the block to move. + t_pl_loc from = place_ctx.block_locs[b_from].loc; + std::cout << "The block to move is at: " << from.x << ", " << from.y << std::endl; + auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); + auto grid_from_type = device_ctx.grid[from.x][from.y].type; + VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); + + + //Retrieving the compressed block grid for this block type + const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; + + //Checking if the block has a compatible subtile. + auto to_type = device_ctx.grid[to.x][to.y].type; + auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); + + //No compatible subtile is found. + if(std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { + return e_create_move::ABORT; + } + + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + return create_move; +} + +//Checks if the are any compatible subtiles with the moving block type. +bool find_to_loc_manual_move(t_logical_block_type_ptr type, t_pl_loc& to) { + + //Retrieve the comporessed block grid for this block type + const auto& compressed_block_grid = g_vpr_ctx.placement().compressed_block_grids[type->index]; + auto to_type = g_vpr_ctx.device().grid[to.x][to.y].type; + auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); + //Checking for the to subtile in a vector. No compatible subtile was found + if(std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) != compatible_subtiles.end()) { + return false; + } + return true; +} + +void cost_summary() { + + std::cout << "\n"; + std::cout << "In cost summary window" << std::endl; + std::cout << "Delta cost: " << manual_moves_global.manual_move_info.delta_cost << std::endl; + std::cout << "Delta timing: " << manual_moves_global.manual_move_info.delta_timing << std::endl; + std::cout << "Delta bouding box: " << manual_moves_global.manual_move_info.delta_bounding_box << std::endl; + + //if(!manual_moves_global.cost_window_is_open) { + + //Window settings + GtkWidget* cost_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position((GtkWindow*)cost_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*)cost_window, "Move Costs"); + + //Creating grid and labels + GtkWidget* grid = gtk_grid_new(); + GtkWidget* title = gtk_label_new(NULL); + gtk_label_set_markup((GtkLabel*)title, "Move Costs and Outcomes"); + std::string delta_cost_label = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost); + GtkWidget* dc = gtk_label_new(delta_cost_label.c_str()); + std::string delta_bounding_box_label = "Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box); + GtkWidget* dbbc = gtk_label_new(delta_bounding_box_label.c_str()); + std::string delta_timing_label = "Delta Timing: " +std::to_string(manual_moves_global.manual_move_info.delta_timing); + GtkWidget* dtc = gtk_label_new(delta_timing_label.c_str()); + std::string outcome = e_move_result_to_string(manual_moves_global.manual_move_info.placer_move_outcome); + std::string move_outcome_label = "Move outcome: " + outcome; + GtkWidget* mo = gtk_label_new(move_outcome_label.c_str()); + + //Adding buttons + GtkWidget* accept = gtk_button_new_with_label("Accept"); + GtkWidget* reject = gtk_button_new_with_label("Reject"); + + //Attach to grid + gtk_grid_attach((GtkGrid*)grid, title, 0, 0, 2, 1); + gtk_grid_attach((GtkGrid*)grid, dc, 0, 1, 2, 1); + gtk_grid_attach((GtkGrid*)grid, dbbc, 0, 2, 2, 1); + gtk_grid_attach((GtkGrid*)grid, dtc, 0, 3, 2, 1); + gtk_grid_attach((GtkGrid*)grid, mo, 0, 4, 2, 1); + gtk_grid_attach((GtkGrid*)grid, accept, 0, 5, 1, 1); + gtk_grid_attach((GtkGrid*)grid, reject, 1, 5, 1, 1); + + //Set margins + gtk_widget_set_halign(accept, GTK_ALIGN_CENTER); + gtk_widget_set_halign(reject, GTK_ALIGN_CENTER); + gtk_widget_set_margin_bottom(grid, 20); + gtk_widget_set_margin_top(grid, 20); + gtk_widget_set_margin_end(grid, 20); + gtk_widget_set_margin_start(grid, 20); + gtk_widget_set_margin_bottom(title, 15); + gtk_widget_set_margin_bottom(dc, 5); + gtk_widget_set_margin_bottom(dbbc, 5); + gtk_widget_set_margin_bottom(dtc, 5); + gtk_widget_set_margin_bottom(mo, 15); + + //Callback functions for the buttons. + g_signal_connect(accept, "clicked", G_CALLBACK(accept_manual_move_window), cost_window); + g_signal_connect(reject, "clicked", G_CALLBACK(reject_manual_move_window), cost_window); + + gtk_container_add(GTK_CONTAINER(cost_window), grid); + + if(manual_moves_global.mm_window_is_open) { + gtk_widget_show_all(cost_window); + } +} + +void accept_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window) { + + std::cout << "User accepted manual move" << std::endl; + //User accepts the manual move, and windows are destroyed. + manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + manual_moves_global.mm_window_is_open = false; + gtk_widget_destroy((GtkWidget*)cost_window); + gtk_widget_destroy(manual_moves_global.manual_move_window); +} + +void reject_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window) { + + std::cout << "User rejected manual move" << std::endl; + //User rejects the manual move, and windows are destroyed. + manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + manual_moves_global.mm_window_is_open = false; + gtk_widget_destroy((GtkWidget*)cost_window); + gtk_widget_destroy(manual_moves_global.manual_move_window); +} + +void close_manual_moves_window() { + manual_moves_global.mm_window_is_open = false; +} + + + + + + + + + +#endif diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h new file mode 100644 index 00000000000..cd9e33c37ef --- /dev/null +++ b/vpr/src/draw/manual_moves.h @@ -0,0 +1,69 @@ +#ifndef MANUAL_MOVES_H +#define MANUAL_MOVES_H + +/** This file contains all functions for manual moves **/ +#ifndef NO_GRAPHICS + +# include "draw_global.h" +# include "draw_global.h" +# include "move_utils.h" +# include "move_generator.h" +# include "ezgl/application.hpp" +# include "ezgl/graphics.hpp" + +# include +# include +# include +# include +# include +# include +# include +# include + +struct ManualMovesInfo { + int blockID = -1; + int x_pos = -1; + int y_pos = -1; + int subtile = 0; + double delta_cost = 0; + double delta_timing = 0; + double delta_bounding_box = 0; + bool valid_input = true; + t_pl_loc to_location; + e_move_result placer_move_outcome = ABORTED; + e_move_result user_move_outcome = ABORTED; +}; + +struct ManualMovesGlobals { + ManualMovesInfo manual_move_info; + bool mm_window_is_open = false; + GtkWidget* manual_move_window; + bool cost_window_is_open = false; +}; + +/** Manual Moves Generator, inherits from MoveGenerator **/ +class ManualMoveGenerator: public MoveGenerator { + public: + //Evaluates if move is successful and legal or unable to do. + e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/); +}; + +//extern ManualMovesGlobals manual_moves_global; + +/** manual moves functions **/ +void draw_manual_moves_window(std::string block_id); +void close_manual_moves_window(); +void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); +bool string_is_a_number(std::string block_id); +void cost_summary(); +bool find_to_loc_manual_move(t_logical_block_type_ptr type, t_pl_loc& to); +ManualMovesInfo* get_manual_move_info(); +ManualMovesGlobals* get_manual_moves_global(); +void accept_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window); +void reject_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window); + + + +#endif /*NO_GRAPHICS */ + +#endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 84f34bf27d7..e89cf093807 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -843,3 +843,8 @@ bool find_compatible_compressed_loc_in_range(t_logical_block_type_ptr type, int } return legal; } + +std::string e_move_result_to_string(e_move_result move_outcome) { + std::string move_result_to_string[] = {"Rejected", "Accepted", "Aborted"}; + return move_result_to_string[move_outcome]; +} diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index eeef5949a58..210799f2df3 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -171,4 +171,6 @@ void compressed_grid_to_loc(t_logical_block_type_ptr blk_type, int cx, int cy, t */ bool find_compatible_compressed_loc_in_range(t_logical_block_type_ptr type, int min_cx, int max_cx, int min_cy, int max_cy, int delta_cx, int cx_from, int cy_from, int& cx_to, int& cy_to, bool is_median); +std::string e_move_result_to_string(e_move_result move_outcome); + #endif diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index aabd02c95a9..4dedf3a938e 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -39,6 +39,7 @@ #include "move_utils.h" #include "read_place.h" #include "place_constraints.h" +#include "manual_moves.h" #include "static_move_generator.h" #include "simpleRL_move_generator.h" @@ -256,6 +257,7 @@ static void reset_move_nets(int num_nets_affected); static e_move_result try_swap(const t_annealing_state* state, t_placer_costs* costs, MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, SetupTimingInfo* timing_info, ClusteredPinTimingInvalidator* pin_timing_invalidator, t_pl_blocks_to_be_moved& blocks_affected, @@ -289,6 +291,7 @@ static float starting_t(const t_annealing_state* state, PlacerSetupSlacks* setup_slacks, SetupTimingInfo* timing_info, MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, ClusteredPinTimingInvalidator* pin_timing_invalidator, t_pl_blocks_to_be_moved& blocks_affected, const t_placer_opts& placer_opts, @@ -367,6 +370,7 @@ static void placement_inner_loop(const t_annealing_state* state, PlacerCriticalities* criticalities, PlacerSetupSlacks* setup_slacks, MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, t_pl_blocks_to_be_moved& blocks_affected, SetupTimingInfo* timing_info, const t_place_algorithm& place_algorithm, @@ -448,6 +452,7 @@ void try_place(const t_placer_opts& placer_opts, std::unique_ptr place_delay_model; std::unique_ptr move_generator; std::unique_ptr move_generator2; + std::unique_ptr manual_move_generator; std::unique_ptr placer_setup_slacks; std::unique_ptr placer_criticalities; @@ -678,6 +683,7 @@ void try_place(const t_placer_opts& placer_opts, placer_setup_slacks.get(), timing_info.get(), *move_generator, + *manual_move_generator, pin_timing_invalidator.get(), blocks_affected, placer_opts, @@ -753,6 +759,7 @@ void try_place(const t_placer_opts& placer_opts, placer_criticalities.get(), placer_setup_slacks.get(), *current_move_generator, + *manual_move_generator, blocks_affected, timing_info.get(), placer_opts.place_algorithm, @@ -820,6 +827,7 @@ void try_place(const t_placer_opts& placer_opts, placer_criticalities.get(), placer_setup_slacks.get(), *current_move_generator, + *manual_move_generator, blocks_affected, timing_info.get(), placer_opts.place_quench_algorithm, @@ -993,6 +1001,7 @@ static void placement_inner_loop(const t_annealing_state* state, PlacerCriticalities* criticalities, PlacerSetupSlacks* setup_slacks, MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, t_pl_blocks_to_be_moved& blocks_affected, SetupTimingInfo* timing_info, const t_place_algorithm& place_algorithm, @@ -1011,6 +1020,7 @@ static void placement_inner_loop(const t_annealing_state* state, e_move_result swap_result = try_swap(state, costs, move_generator, + manual_move_generator, timing_info, pin_timing_invalidator, blocks_affected, @@ -1144,6 +1154,7 @@ static float starting_t(const t_annealing_state* state, PlacerSetupSlacks* setup_slacks, SetupTimingInfo* timing_info, MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, ClusteredPinTimingInvalidator* pin_timing_invalidator, t_pl_blocks_to_be_moved& blocks_affected, const t_placer_opts& placer_opts, @@ -1168,6 +1179,7 @@ static float starting_t(const t_annealing_state* state, e_move_result swap_result = try_swap(state, costs, move_generator, + manual_move_generator, timing_info, pin_timing_invalidator, blocks_affected, @@ -1260,6 +1272,7 @@ static void reset_move_nets(int num_nets_affected) { static e_move_result try_swap(const t_annealing_state* state, t_placer_costs* costs, MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, SetupTimingInfo* timing_info, ClusteredPinTimingInvalidator* pin_timing_invalidator, t_pl_blocks_to_be_moved& blocks_affected, @@ -1276,6 +1289,8 @@ static e_move_result try_swap(const t_annealing_state* state, * Returns whether the swap is accepted, rejected or aborted. * * Passes back the new value of the cost functions. */ + std::cout << "In the try swap function" << std::endl; + float rlim_escape_fraction = placer_opts.rlim_escape_fraction; float timing_tradeoff = placer_opts.timing_tradeoff; @@ -1295,7 +1310,7 @@ static e_move_result try_swap(const t_annealing_state* state, double delta_c = 0; //Change in cost due to this swap. double bb_delta_c = 0; //Change in the bounding box (wiring) cost. double timing_delta_c = 0; //Change in the timing cost (delay * criticality). - + /* Allow some fraction of moves to not be restricted by rlim, */ /* in the hopes of better escaping local minima. */ float rlim; @@ -1305,15 +1320,35 @@ static e_move_result try_swap(const t_annealing_state* state, rlim = state->rlim; } +#ifndef NO_GRAPHICS + + bool manual_move_flag = false; + manual_move_flag = get_manual_move_flag(); + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + + if(manual_move_flag) { + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + } + +#endif /* NO_GRAPHICS */ + + e_create_move create_move_outcome; + + if(manual_move_flag) { + create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); + } + else { //Generate a new move (perturbation) used to explore the space of possible placements - e_create_move create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + } ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); e_move_result move_outcome = ABORTED; - if (create_move_outcome == e_create_move::ABORT) { + if (create_move_outcome == e_create_move::ABORT || (manual_move_flag && !manual_move_global->manual_move_info.valid_input)) { LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), @@ -1398,6 +1433,33 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); + if(manual_move_flag && manual_move_global->manual_move_info.valid_input) { + + std::cout << "Manual move is valid" << std::endl; + manual_move_global->manual_move_info.delta_cost = delta_c; + manual_move_global->manual_move_info.delta_timing = timing_delta_c; + manual_move_global->manual_move_info.delta_bounding_box = bb_delta_c; + manual_move_global->manual_move_info.placer_move_outcome = move_outcome; + + cost_summary(); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + + std::cout << "After cost window summary" << std::endl; + move_outcome = manual_move_global->manual_move_info.user_move_outcome; + std::cout << "Move outcome after summary window: " << manual_move_global->manual_move_info.user_move_outcome << std::endl; + std::cout << "Move outcome after assigned: " << move_outcome << std::endl; + + /*//Highlighting the block in the new position. + ClusterBlockId clb_index = ClusterBlockId(manual_move_global->manual_move_info.blockID); + //Unselects all blocks first + deselect_all(); + //Highlight block in the new position requested by user + auto& cluster_ctx = g_vpr_ctx.clustering(); + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index);*/ + + + } + if (move_outcome == ACCEPTED) { costs->cost += delta_c; costs->bb_cost += bb_delta_c; @@ -1490,7 +1552,7 @@ static e_move_result try_swap(const t_annealing_state* state, #ifdef VTR_ENABLE_DEBUG_LOGGING # ifndef NO_GRAPHICS - stop_placement_and_check_breakpoints(blocks_affected, move_outcome, delta_c, bb_delta_c, timing_delta_c); + stop_placement_and_check_breakpoints(blocks_affected, move_outcome, delta_c, bb_delta_c, timing_delta_c); # endif #endif @@ -2903,3 +2965,21 @@ static void calculate_reward_and_process_outcome(const t_placer_opts& placer_opt bool placer_needs_lookahead(const t_vpr_setup& vpr_setup) { return (vpr_setup.PlacerOpts.place_algorithm.is_timing_driven()); } + +void manual_move_info_from_user_and_open_window(ManualMovesInfo* manual_move_info) { + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); +} + +void update_manual_move_cost_and_open_window(ManualMovesInfo* manual_move_info, e_move_result& move_outcome, double delta_c, double delta_bb, double delta_t) { + manual_move_info->delta_cost = delta_c; + manual_move_info->delta_bounding_box = delta_bb; + manual_move_info->delta_timing = delta_t; + manual_move_info->placer_move_outcome = move_outcome; + cost_summary(); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + move_outcome = manual_move_info->user_move_outcome; + + //Have to add user placement outcome after if move is accepted +} + diff --git a/vpr/src/place/place.h b/vpr/src/place/place.h index 514fe0e9306..c56c4ab6d34 100644 --- a/vpr/src/place/place.h +++ b/vpr/src/place/place.h @@ -2,6 +2,7 @@ #define VPR_PLACE_H #include "vpr_types.h" +#include "manual_moves.h" void try_place(const t_placer_opts& placer_opts, t_annealing_sched annealing_sched, const t_router_opts& router_opts, @@ -13,4 +14,7 @@ void try_place(const t_placer_opts& placer_opts, int num_directs); bool placer_needs_lookahead(const t_vpr_setup& vpr_setup); +void manual_move_info_from_user_and_open_window(ManualMovesInfo* manual_move_info); +//void update_manual_move_cost_and_open_window(ManualMovesInfo* manual_move_info, e_move_result& move_outcome, double delta_c, double delta_bb, double delta_t); + #endif diff --git a/vpr/src/place/placer_breakpoint.cpp b/vpr/src/place/placer_breakpoint.cpp index 4b23862daf9..f4bb1639089 100644 --- a/vpr/src/place/placer_breakpoint.cpp +++ b/vpr/src/place/placer_breakpoint.cpp @@ -18,6 +18,7 @@ void transform_blocks_affected(t_pl_blocks_to_be_moved blocksAffected) { } void stop_placement_and_check_breakpoints(t_pl_blocks_to_be_moved& blocks_affected, e_move_result move_outcome, double delta_c, double bb_delta_c, double timing_delta_c) { + t_draw_state* draw_state = get_draw_state_vars(); if (draw_state->list_of_breakpoints.size() != 0) { //update current information From accf0e101dfe9411c779b2d3a67f43858c091952 Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 22 Jun 2021 16:49:13 -0400 Subject: [PATCH 04/46] Fixed segmentation faults and added new gtk features --- vpr/src/draw/draw.cpp | 7906 +++++++++++++++++---------------- vpr/src/draw/manual_moves.cpp | 450 +- vpr/src/draw/manual_moves.h | 18 +- vpr/src/place/move_utils.cpp | 11 + vpr/src/place/place.cpp | 4588 +++++++++---------- vpr/src/place/place.h | 3 +- 6 files changed, 6740 insertions(+), 6236 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index d3288816ad0..1d57fef1909 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -86,82 +86,119 @@ //#define TIME_DRAWSCREEN /* Enable if want to track runtime for drawscreen() */ /********************** Subroutines local to this module ********************/ -static void drawplace(ezgl::renderer* g); -static void drawnets(ezgl::renderer* g); -static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer* g); -static void draw_congestion(ezgl::renderer* g); -static void draw_routing_costs(ezgl::renderer* g); -static void draw_routing_bb(ezgl::renderer* g); -static void draw_routing_util(ezgl::renderer* g); -static void draw_crit_path(ezgl::renderer* g); -static void draw_placement_macros(ezgl::renderer* g); - -void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* key_name); -void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, double y); -void act_on_mouse_move(ezgl::application* app, GdkEventButton* event, double x, double y); - -static void draw_routed_net(ClusterNetId net, ezgl::renderer* g); -void draw_partial_route(const std::vector& rr_nodes_to_draw, ezgl::renderer* g); -static void draw_rr(ezgl::renderer* g); -static void draw_rr_edges(int from_node, ezgl::renderer* g); -static void draw_rr_pin(int inode, const ezgl::color& color, ezgl::renderer* g); -static void draw_rr_chan(int inode, const ezgl::color color, ezgl::renderer* g); -static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer* g); -static void draw_pin_to_chan_edge(int pin_node, int chan_node, ezgl::renderer* g); -static void draw_get_rr_src_sink_coords(const t_rr_node& node, float* xcen, float* ycen); -static void draw_x(float x, float y, float size, ezgl::renderer* g); -static void draw_pin_to_pin(int opin, int ipin, ezgl::renderer* g); -static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer* g); -static void draw_source_to_pin(int source_node, int opin_node, ezgl::renderer* g); -static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, bool buffered, bool switch_configurable, ezgl::renderer* g); -static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, short switch_type, ezgl::renderer* g); -static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, short switch_type, ezgl::renderer* g); -static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, int chany_node, int chany_track, enum e_edge_dir edge_dir, short switch_type, ezgl::renderer* g); -static int get_track_num(int inode, const vtr::OffsetMatrix& chanx_track, const vtr::OffsetMatrix& chany_track); +static void drawplace(ezgl::renderer *g); +static void drawnets(ezgl::renderer *g); +static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer *g); +static void draw_congestion(ezgl::renderer *g); +static void draw_routing_costs(ezgl::renderer *g); +static void draw_routing_bb(ezgl::renderer *g); +static void draw_routing_util(ezgl::renderer *g); +static void draw_crit_path(ezgl::renderer *g); +static void draw_placement_macros(ezgl::renderer *g); + +void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, + char *key_name); +void act_on_mouse_press(ezgl::application *app, GdkEventButton *event, double x, + double y); +void act_on_mouse_move(ezgl::application *app, GdkEventButton *event, double x, + double y); + +static void draw_routed_net(ClusterNetId net, ezgl::renderer *g); +void draw_partial_route(const std::vector &rr_nodes_to_draw, + ezgl::renderer *g); +static void draw_rr(ezgl::renderer *g); +static void draw_rr_edges(int from_node, ezgl::renderer *g); +static void draw_rr_pin(int inode, const ezgl::color &color, ezgl::renderer *g); +static void draw_rr_chan(int inode, const ezgl::color color, ezgl::renderer *g); +static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer *g); +static void draw_pin_to_chan_edge(int pin_node, int chan_node, + ezgl::renderer *g); +static void draw_get_rr_src_sink_coords(const t_rr_node &node, float *xcen, + float *ycen); +static void draw_x(float x, float y, float size, ezgl::renderer *g); +static void draw_pin_to_pin(int opin, int ipin, ezgl::renderer *g); +static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer *g); +static void draw_source_to_pin(int source_node, int opin_node, + ezgl::renderer *g); +static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, + bool buffered, bool switch_configurable, ezgl::renderer *g); +static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, + short switch_type, ezgl::renderer *g); +static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, + short switch_type, ezgl::renderer *g); +static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, + int chany_node, int chany_track, enum e_edge_dir edge_dir, + short switch_type, ezgl::renderer *g); +static int get_track_num(int inode, const vtr::OffsetMatrix &chanx_track, + const vtr::OffsetMatrix &chany_track); static bool draw_if_net_highlighted(ClusterNetId inet); static int draw_check_rr_node_hit(float click_x, float click_y); -static void draw_expand_non_configurable_rr_nodes_recurr(int from_node, std::set& expanded_nodes); +static void draw_expand_non_configurable_rr_nodes_recurr(int from_node, + std::set &expanded_nodes); static bool highlight_rr_nodes(float x, float y); static void highlight_blocks(double x, double y); static void draw_reset_blk_colors(); static void draw_reset_blk_color(ClusterBlockId blk_id); -static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, float height, int size, ezgl::renderer* g); -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, ezgl::renderer* g); -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, float width, float height_scale, ezgl::renderer* g); - -static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, float incr_delay, ezgl::renderer* g); -static void draw_routed_timing_edge(tatum::NodeId start_tnode, tatum::NodeId end_tnode, float incr_delay, ezgl::color color, ezgl::renderer* g); -static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, tatum::NodeId sink_tnode, ezgl::color color, ezgl::renderer* g); -static std::vector trace_routed_connection_rr_nodes(const ClusterNetId net_id, const int driver_pin, const int sink_pin); -static bool trace_routed_connection_rr_nodes_recurr(const t_rt_node* rt_node, int sink_rr_node, std::vector& rr_nodes_on_path); +static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, + float height, int size, ezgl::renderer *g); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, + float height, ezgl::renderer *g); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, + float height, float width, float height_scale, ezgl::renderer *g); + +static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, + float incr_delay, ezgl::renderer *g); +static void draw_routed_timing_edge(tatum::NodeId start_tnode, + tatum::NodeId end_tnode, float incr_delay, ezgl::color color, + ezgl::renderer *g); +static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, + tatum::NodeId sink_tnode, ezgl::color color, ezgl::renderer *g); +static std::vector trace_routed_connection_rr_nodes( + const ClusterNetId net_id, const int driver_pin, const int sink_pin); +static bool trace_routed_connection_rr_nodes_recurr(const t_rt_node *rt_node, + int sink_rr_node, std::vector &rr_nodes_on_path); static t_edge_size find_edge(int prev_inode, int inode); -static void draw_color_map_legend(const vtr::ColorMap& cmap, ezgl::renderer* g); +static void draw_color_map_legend(const vtr::ColorMap &cmap, ezgl::renderer *g); ezgl::color lighten_color(ezgl::color color, float amount); static void draw_block_pin_util(); -static float get_router_expansion_cost(const t_rr_node_route_inf node_inf, e_draw_router_expansion_cost draw_router_expansion_cost); -static void draw_router_expansion_costs(ezgl::renderer* g); - -static void draw_rr_costs(ezgl::renderer* g, const std::vector& rr_costs, bool lowest_cost_first = true); -static void draw_main_canvas(ezgl::renderer* g); -static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application* app, bool is_new_window); -static void initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path(ezgl::application* app, bool is_new_window); -static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application* app, bool is_new_window); -static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application* app, bool is_new_window); -static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application* app, bool is_new_window); -static void initial_setup_NO_PICTURE_to_ROUTING_with_crit_path(ezgl::application* app, bool is_new_window); -static void toggle_window_mode(GtkWidget* /*widget*/, ezgl::application* /*app*/); -static void setup_default_ezgl_callbacks(ezgl::application* app); -static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -static void set_block_outline(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); -static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); -static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); -static void manual_moves_callback(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/, ezgl::application* app); +static float get_router_expansion_cost(const t_rr_node_route_inf node_inf, + e_draw_router_expansion_cost draw_router_expansion_cost); +static void draw_router_expansion_costs(ezgl::renderer *g); + +static void draw_rr_costs(ezgl::renderer *g, const std::vector &rr_costs, + bool lowest_cost_first = true); +static void draw_main_canvas(ezgl::renderer *g); +static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application *app, + bool is_new_window); +static void initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path( + ezgl::application *app, bool is_new_window); +static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application *app, + bool is_new_window); +static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application *app, + bool is_new_window); +static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application *app, + bool is_new_window); +static void initial_setup_NO_PICTURE_to_ROUTING_with_crit_path( + ezgl::application *app, bool is_new_window); +static void toggle_window_mode(GtkWidget* /*widget*/, + ezgl::application* /*app*/); +static void setup_default_ezgl_callbacks(ezgl::application *app); +static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/); +static void set_block_outline(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/); +static void set_block_text(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/); +static void clip_routing_util(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/); +static void manual_moves_callback(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/, ezgl::application *app); static void run_graphics_commands(std::string commands); /************************** File Scope Variables ****************************/ @@ -177,35 +214,34 @@ constexpr float EMPTY_BLOCK_LIGHTEN_FACTOR = 0.20; //a subset of selected net) where it is important for them to be visually distinct. const std::vector kelly_max_contrast_colors = { - //ezgl::color(242, 243, 244), //white: skip white since it doesn't contrast well with VPR's light background - ezgl::color(34, 34, 34), //black - ezgl::color(243, 195, 0), //yellow - ezgl::color(135, 86, 146), //purple - ezgl::color(243, 132, 0), //orange - ezgl::color(161, 202, 241), //light blue - ezgl::color(190, 0, 50), //red - ezgl::color(194, 178, 128), //buf - ezgl::color(132, 132, 130), //gray - ezgl::color(0, 136, 86), //green - ezgl::color(230, 143, 172), //purplish pink - ezgl::color(0, 103, 165), //blue - ezgl::color(249, 147, 121), //yellowish pink - ezgl::color(96, 78, 151), //violet - ezgl::color(246, 166, 0), //orange yellow - ezgl::color(179, 68, 108), //purplish red - ezgl::color(220, 211, 0), //greenish yellow - ezgl::color(136, 45, 23), //redish brown - ezgl::color(141, 182, 0), //yellow green - ezgl::color(101, 69, 34), //yellowish brown - ezgl::color(226, 88, 34), //reddish orange - ezgl::color(43, 61, 38) //olive green -}; - -ezgl::application::settings settings("/ezgl/main.ui", - "MainWindow", - "MainCanvas", - "org.verilogtorouting.vpr.PID" + std::to_string(vtr::get_pid()), - setup_default_ezgl_callbacks); +//ezgl::color(242, 243, 244), //white: skip white since it doesn't contrast well with VPR's light background + ezgl::color(34, 34, 34), //black + ezgl::color(243, 195, 0), //yellow + ezgl::color(135, 86, 146), //purple + ezgl::color(243, 132, 0), //orange + ezgl::color(161, 202, 241), //light blue + ezgl::color(190, 0, 50), //red + ezgl::color(194, 178, 128), //buf + ezgl::color(132, 132, 130), //gray + ezgl::color(0, 136, 86), //green + ezgl::color(230, 143, 172), //purplish pink + ezgl::color(0, 103, 165), //blue + ezgl::color(249, 147, 121), //yellowish pink + ezgl::color(96, 78, 151), //violet + ezgl::color(246, 166, 0), //orange yellow + ezgl::color(179, 68, 108), //purplish red + ezgl::color(220, 211, 0), //greenish yellow + ezgl::color(136, 45, 23), //redish brown + ezgl::color(141, 182, 0), //yellow green + ezgl::color(101, 69, 34), //yellowish brown + ezgl::color(226, 88, 34), //reddish orange + ezgl::color(43, 61, 38) //olive green + }; + +ezgl::application::settings settings("/ezgl/main.ui", "MainWindow", + "MainCanvas", + "org.verilogtorouting.vpr.PID" + std::to_string(vtr::get_pid()), + setup_default_ezgl_callbacks); ezgl::application application(settings); //bool mm_window = false; @@ -219,20 +255,22 @@ std::string rr_highlight_message; /********************** Subroutine definitions ******************************/ -void init_graphics_state(bool show_graphics_val, int gr_automode_val, enum e_route_type route_type, bool save_graphics, std::string graphics_commands) { +void init_graphics_state(bool show_graphics_val, int gr_automode_val, + enum e_route_type route_type, bool save_graphics, + std::string graphics_commands) { #ifndef NO_GRAPHICS - /* Call accessor functions to retrieve global variables. */ - t_draw_state* draw_state = get_draw_state_vars(); + /* Call accessor functions to retrieve global variables. */ + t_draw_state *draw_state = get_draw_state_vars(); - /* 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. */ + /* 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. */ - draw_state->show_graphics = show_graphics_val; - draw_state->gr_automode = gr_automode_val; - draw_state->draw_route_type = route_type; - draw_state->save_graphics = save_graphics; - draw_state->graphics_commands = graphics_commands; + draw_state->show_graphics = show_graphics_val; + draw_state->gr_automode = gr_automode_val; + draw_state->draw_route_type = route_type; + draw_state->save_graphics = save_graphics; + draw_state->graphics_commands = graphics_commands; #else //Suppress unused parameter warnings @@ -245,292 +283,316 @@ void init_graphics_state(bool show_graphics_val, int gr_automode_val, enum e_rou } #ifndef NO_GRAPHICS -static void draw_main_canvas(ezgl::renderer* g) { - t_draw_state* draw_state = get_draw_state_vars(); +static void draw_main_canvas(ezgl::renderer *g) { + t_draw_state *draw_state = get_draw_state_vars(); - g->set_font_size(14); + g->set_font_size(14); - 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 == PLACEMENT) { - switch (draw_state->show_nets) { - case DRAW_NETS: - drawnets(g); - break; - case DRAW_LOGICAL_CONNECTIONS: - break; - default: - break; - } - } else { /* ROUTING on screen */ + if (draw_state->pic_on_screen == PLACEMENT) { + switch (draw_state->show_nets) { + case DRAW_NETS: + drawnets(g); + break; + case DRAW_LOGICAL_CONNECTIONS: + break; + default: + break; + } + } else { /* ROUTING on screen */ - switch (draw_state->show_nets) { - case DRAW_NETS: - drawroute(ALL_NETS, g); - break; - case DRAW_LOGICAL_CONNECTIONS: - // fall through - default: - draw_rr(g); - break; - } + switch (draw_state->show_nets) { + case DRAW_NETS: + drawroute(ALL_NETS, g); + break; + case DRAW_LOGICAL_CONNECTIONS: + // fall through + default: + draw_rr(g); + break; + } - 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); - draw_crit_path(g); + draw_crit_path(g); - draw_logical_connections(g); + draw_logical_connections(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 + } - if (draw_state->auto_proceed) { - //Automatically exit the event loop, so user's don't need to manually click proceed + if (draw_state->auto_proceed) { + //Automatically exit the event loop, so user's don't need to manually click proceed - //Avoid trying to repeatedly exit (which would cause errors in GTK) - draw_state->auto_proceed = false; + //Avoid trying to repeatedly exit (which would cause errors in GTK) + draw_state->auto_proceed = false; - application.quit(); //Ensure we leave the event loop - } + application.quit(); //Ensure we leave the event loop + } } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_PLACEMENT */ -static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application* app, bool is_new_window) { - if (!is_new_window) return; - - //button to enter window_mode, created in main.ui - GtkButton* window = (GtkButton*)app->get_object("Window"); - gtk_button_set_label(window, "Window"); - g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); - - //button to search, created in main.ui - GtkButton* search = (GtkButton*)app->get_object("Search"); - gtk_button_set_label(search, "Search"); - g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); - - //button for save graphcis, created in main.ui - GtkButton* save = (GtkButton*)app->get_object("SaveGraphics"); - g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), app); - - //combo box for search type, created in main.ui - GObject* search_type = (GObject*)app->get_object("SearchType"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); // index 0 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block Name"); // index 1 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); // index 2 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); // index 3 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "RR Node ID"); // index 4 - gtk_combo_box_set_active((GtkComboBox*)search_type, 0); // default set to Block ID which has an index 0 - - button_for_toggle_nets(); - button_for_net_max_fanout(); - button_for_net_alpha(); - button_for_toggle_blk_internal(); - button_for_toggle_block_pin_util(); - button_for_toggle_placement_macros(); +static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application *app, + bool is_new_window) { + if (!is_new_window) + return; + + //button to enter window_mode, created in main.ui + GtkButton *window = (GtkButton*) app->get_object("Window"); + gtk_button_set_label(window, "Window"); + g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); + + //button to search, created in main.ui + GtkButton *search = (GtkButton*) app->get_object("Search"); + gtk_button_set_label(search, "Search"); + g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); + + //button for save graphcis, created in main.ui + GtkButton *save = (GtkButton*) app->get_object("SaveGraphics"); + g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), + app); + + //combo box for search type, created in main.ui + GObject *search_type = (GObject*) app->get_object("SearchType"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); // index 0 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "Block Name"); // index 1 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); // index 2 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); // index 3 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "RR Node ID"); // index 4 + gtk_combo_box_set_active((GtkComboBox*) search_type, 0); // default set to Block ID which has an index 0 + + button_for_toggle_nets(); + button_for_net_max_fanout(); + button_for_net_alpha(); + button_for_toggle_blk_internal(); + button_for_toggle_block_pin_util(); + button_for_toggle_placement_macros(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_PLACEMENT_with_crit_path */ -static void initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path(ezgl::application* app, bool is_new_window) { - initial_setup_NO_PICTURE_to_PLACEMENT(app, is_new_window); - button_for_toggle_crit_path(); +static void initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path( + ezgl::application *app, bool is_new_window) { + initial_setup_NO_PICTURE_to_PLACEMENT(app, is_new_window); + button_for_toggle_crit_path(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * PLACEMENT_to_ROUTING */ -static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application* app, bool is_new_window) { - initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path(app, is_new_window); - button_for_toggle_rr(); - button_for_toggle_congestion(); - button_for_toggle_congestion_cost(); - button_for_toggle_routing_bounding_box(); - button_for_toggle_routing_util(); - button_for_toggle_router_expansion_costs(); +static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application *app, + bool is_new_window) { + initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path(app, is_new_window); + button_for_toggle_rr(); + button_for_toggle_congestion(); + button_for_toggle_congestion_cost(); + button_for_toggle_routing_bounding_box(); + button_for_toggle_routing_util(); + button_for_toggle_router_expansion_costs(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * ROUTING_to_PLACEMENT */ -static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application* app, bool is_new_window) { - initial_setup_PLACEMENT_to_ROUTING(app, is_new_window); - std::string toggle_rr = "toggle_rr"; - std::string toggle_congestion = "toggle_congestion"; - std::string toggle_routing_congestion_cost = "toggle_routing_congestion_cost"; - std::string toggle_routing_bounding_box = "toggle_routing_bounding_box"; - std::string toggle_routing_util = "toggle_rr"; - std::string toggle_router_expansion_costs = "toggle_router_expansion_costs"; - - delete_button(toggle_rr.c_str()); - delete_button(toggle_congestion.c_str()); - delete_button(toggle_routing_congestion_cost.c_str()); - delete_button(toggle_routing_bounding_box.c_str()); - delete_button(toggle_routing_util.c_str()); - delete_button(toggle_router_expansion_costs.c_str()); +static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application *app, + bool is_new_window) { + initial_setup_PLACEMENT_to_ROUTING(app, is_new_window); + std::string toggle_rr = "toggle_rr"; + std::string toggle_congestion = "toggle_congestion"; + std::string toggle_routing_congestion_cost = + "toggle_routing_congestion_cost"; + std::string toggle_routing_bounding_box = "toggle_routing_bounding_box"; + std::string toggle_routing_util = "toggle_rr"; + std::string toggle_router_expansion_costs = "toggle_router_expansion_costs"; + + delete_button(toggle_rr.c_str()); + delete_button(toggle_congestion.c_str()); + delete_button(toggle_routing_congestion_cost.c_str()); + delete_button(toggle_routing_bounding_box.c_str()); + delete_button(toggle_routing_util.c_str()); + delete_button(toggle_router_expansion_costs.c_str()); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_ROUTING */ -static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application* app, bool is_new_window) { - if (!is_new_window) return; - - GtkButton* window = (GtkButton*)app->get_object("Window"); - gtk_button_set_label(window, "Window"); - g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); - - GtkButton* search = (GtkButton*)app->get_object("Search"); - gtk_button_set_label(search, "Search"); - g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); - - GtkButton* save = (GtkButton*)app->get_object("SaveGraphics"); - g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), app); - - GObject* search_type = (GObject*)app->get_object("SearchType"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block Name"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "RR Node ID"); - - button_for_toggle_nets(); - button_for_net_max_fanout(); - button_for_net_alpha(); - button_for_toggle_blk_internal(); - button_for_toggle_block_pin_util(); - button_for_toggle_placement_macros(); - button_for_toggle_rr(); - button_for_toggle_congestion(); - button_for_toggle_congestion_cost(); - button_for_toggle_routing_bounding_box(); - button_for_toggle_routing_util(); - button_for_toggle_router_expansion_costs(); +static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application *app, + bool is_new_window) { + if (!is_new_window) + return; + + GtkButton *window = (GtkButton*) app->get_object("Window"); + gtk_button_set_label(window, "Window"); + g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); + + GtkButton *search = (GtkButton*) app->get_object("Search"); + gtk_button_set_label(search, "Search"); + g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); + + GtkButton *save = (GtkButton*) app->get_object("SaveGraphics"); + g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), + app); + + GObject *search_type = (GObject*) app->get_object("SearchType"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "Block Name"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "RR Node ID"); + + button_for_toggle_nets(); + button_for_net_max_fanout(); + button_for_net_alpha(); + button_for_toggle_blk_internal(); + button_for_toggle_block_pin_util(); + button_for_toggle_placement_macros(); + button_for_toggle_rr(); + button_for_toggle_congestion(); + button_for_toggle_congestion_cost(); + button_for_toggle_routing_bounding_box(); + button_for_toggle_routing_util(); + button_for_toggle_router_expansion_costs(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_ROUTING_with_crit_path */ -static void initial_setup_NO_PICTURE_to_ROUTING_with_crit_path(ezgl::application* app, bool is_new_window) { - initial_setup_NO_PICTURE_to_ROUTING(app, is_new_window); - button_for_toggle_crit_path(); +static void initial_setup_NO_PICTURE_to_ROUTING_with_crit_path( + ezgl::application *app, bool is_new_window) { + initial_setup_NO_PICTURE_to_ROUTING(app, is_new_window); + button_for_toggle_crit_path(); } #endif //NO_GRAPHICS -void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type pic_on_screen_val, std::shared_ptr setup_timing_info) { +void update_screen(ScreenUpdatePriority priority, const char *msg, + enum pic_type pic_on_screen_val, + std::shared_ptr setup_timing_info) { #ifndef NO_GRAPHICS - /* Updates the screen if the user has requested graphics. The priority * - * 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(); - - if (!draw_state->show_graphics) - ezgl::set_disable_event_loop(true); - else - ezgl::set_disable_event_loop(false); - - ezgl::setup_callback_fn init_setup = nullptr; - - /* If it's the type of picture displayed has changed, set up the proper * - * buttons. */ - if (draw_state->pic_on_screen != pic_on_screen_val) { //State changed - - 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); - } - - draw_state->setup_timing_info = setup_timing_info; - - if (pic_on_screen_val == PLACEMENT && draw_state->pic_on_screen == NO_PICTURE) { - if (setup_timing_info) { - init_setup = initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path; - } else { - init_setup = initial_setup_NO_PICTURE_to_PLACEMENT; - } - draw_state->save_graphics_file_base = "vpr_placement"; - - } else if (pic_on_screen_val == ROUTING && draw_state->pic_on_screen == PLACEMENT) { - //Routing, opening after placement - init_setup = initial_setup_PLACEMENT_to_ROUTING; - draw_state->save_graphics_file_base = "vpr_routing"; - - } else if (pic_on_screen_val == PLACEMENT && draw_state->pic_on_screen == ROUTING) { - init_setup = initial_setup_ROUTING_to_PLACEMENT; - draw_state->save_graphics_file_base = "vpr_placement"; - - } else if (pic_on_screen_val == ROUTING && draw_state->pic_on_screen == NO_PICTURE) { - //Routing opening first - if (setup_timing_info) { - init_setup = initial_setup_NO_PICTURE_to_ROUTING_with_crit_path; - } else { - init_setup = initial_setup_NO_PICTURE_to_ROUTING; - } - draw_state->save_graphics_file_base = "vpr_routing"; - } - - draw_state->pic_on_screen = pic_on_screen_val; - - } else { - //No change (e.g. paused) - init_setup = nullptr; - } - - bool state_change = (init_setup != nullptr); - 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. - //However, by default this causes graphics to pause for user interaction. - // - //If the priority is such that we shouldn't pause we need to continue automatically, so - //the user won't need to click manually. - draw_state->auto_proceed = (state_change && !should_pause); - - if (state_change //Must update buttons - || should_pause //The priority means graphics should pause for user interaction - || draw_state->forced_pause) { //The user asked to pause - - if (draw_state->forced_pause) { - VTR_LOG("Pausing in interactive graphics (user pressed 'Pause')\n"); - draw_state->forced_pause = false; //Reset pause flag - } - - application.run(init_setup, act_on_mouse_press, act_on_mouse_move, act_on_key_press); - - if (!draw_state->graphics_commands.empty()) { - run_graphics_commands(draw_state->graphics_commands); - } - } - - if (draw_state->show_graphics) { - application.update_message(msg); - application.refresh_drawing(); - application.flush_drawing(); - } - - if (draw_state->save_graphics) { - std::string extension = "pdf"; - save_graphics(extension, draw_state->save_graphics_file_base); - } + /* Updates the screen if the user has requested graphics. The priority * + * 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(); + + if (!draw_state->show_graphics) + ezgl::set_disable_event_loop(true); + else + ezgl::set_disable_event_loop(false); + + ezgl::setup_callback_fn init_setup = nullptr; + + /* If it's the type of picture displayed has changed, set up the proper * + * buttons. */ + if (draw_state->pic_on_screen != pic_on_screen_val) { //State changed + + 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); + } + + draw_state->setup_timing_info = setup_timing_info; + + if (pic_on_screen_val == PLACEMENT + && draw_state->pic_on_screen == NO_PICTURE) { + if (setup_timing_info) { + init_setup = + initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path; + } else { + init_setup = initial_setup_NO_PICTURE_to_PLACEMENT; + } + draw_state->save_graphics_file_base = "vpr_placement"; + + } else if (pic_on_screen_val == ROUTING + && draw_state->pic_on_screen == PLACEMENT) { + //Routing, opening after placement + init_setup = initial_setup_PLACEMENT_to_ROUTING; + draw_state->save_graphics_file_base = "vpr_routing"; + + } else if (pic_on_screen_val == PLACEMENT + && draw_state->pic_on_screen == ROUTING) { + init_setup = initial_setup_ROUTING_to_PLACEMENT; + draw_state->save_graphics_file_base = "vpr_placement"; + + } else if (pic_on_screen_val == ROUTING + && draw_state->pic_on_screen == NO_PICTURE) { + //Routing opening first + if (setup_timing_info) { + init_setup = initial_setup_NO_PICTURE_to_ROUTING_with_crit_path; + } else { + init_setup = initial_setup_NO_PICTURE_to_ROUTING; + } + draw_state->save_graphics_file_base = "vpr_routing"; + } + + draw_state->pic_on_screen = pic_on_screen_val; + + } else { + //No change (e.g. paused) + init_setup = nullptr; + } + + bool state_change = (init_setup != nullptr); + 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. + //However, by default this causes graphics to pause for user interaction. + // + //If the priority is such that we shouldn't pause we need to continue automatically, so + //the user won't need to click manually. + draw_state->auto_proceed = (state_change && !should_pause); + + if (state_change //Must update buttons + || should_pause //The priority means graphics should pause for user interaction + || draw_state->forced_pause) { //The user asked to pause + + if (draw_state->forced_pause) { + VTR_LOG("Pausing in interactive graphics (user pressed 'Pause')\n"); + draw_state->forced_pause = false; //Reset pause flag + } + + application.run(init_setup, act_on_mouse_press, act_on_mouse_move, + act_on_key_press); + + if (!draw_state->graphics_commands.empty()) { + run_graphics_commands(draw_state->graphics_commands); + } + } + + if (draw_state->show_graphics) { + application.update_message(msg); + application.refresh_drawing(); + application.flush_drawing(); + } + + if (draw_state->save_graphics) { + std::string extension = "pdf"; + save_graphics(extension, draw_state->save_graphics_file_base); + } #else (void)setup_timing_info; @@ -541,339 +603,369 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type } #ifndef NO_GRAPHICS -static void toggle_window_mode(GtkWidget* /*widget*/, ezgl::application* /*app*/) { - window_mode = true; +static void toggle_window_mode(GtkWidget* /*widget*/, + ezgl::application* /*app*/) { + window_mode = true; } -void toggle_nets(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_nets button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - - // get the pointer to the toggle_nets button - std::string button_name = "toggle_nets"; - auto toggle_nets = find_button(button_name.c_str()); - - // use the pointer to get the active text - enum e_draw_nets new_state; - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_nets)); - - // assign corresponding enum value to draw_state->show_nets - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_NETS; - else if (strcmp(combo_box_content, "Nets") == 0) { - new_state = DRAW_NETS; - } else { // "Logical Connections" - new_state = DRAW_LOGICAL_CONNECTIONS; - } - draw_state->reset_nets_congestion_and_rr(); - draw_state->show_nets = new_state; - - //free dynamically allocated pointers - g_free(combo_box_content); - - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +void toggle_nets(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_nets button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + + // get the pointer to the toggle_nets button + std::string button_name = "toggle_nets"; + auto toggle_nets = find_button(button_name.c_str()); + + // use the pointer to get the active text + enum e_draw_nets new_state; + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_nets)); + + // assign corresponding enum value to draw_state->show_nets + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_NETS; + else if (strcmp(combo_box_content, "Nets") == 0) { + new_state = DRAW_NETS; + } else { // "Logical Connections" + new_state = DRAW_LOGICAL_CONNECTIONS; + } + draw_state->reset_nets_congestion_and_rr(); + draw_state->show_nets = new_state; + + //free dynamically allocated pointers + g_free(combo_box_content); + + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } void toggle_rr(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_rr button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_rr"; - auto toggle_rr = find_button(button_name.c_str()); - - enum e_draw_rr_toggle new_state; - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_rr)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_RR; - else if (strcmp(combo_box_content, "Nodes") == 0) - new_state = DRAW_NODES_RR; - else if (strcmp(combo_box_content, "Nodes SBox") == 0) - new_state = DRAW_NODES_SBOX_RR; - else if (strcmp(combo_box_content, "Nodes SBox CBox") == 0) - new_state = DRAW_NODES_SBOX_CBOX_RR; - else if (strcmp(combo_box_content, "Nodes SBox CBox Internal") == 0) - new_state = DRAW_NODES_SBOX_CBOX_INTERNAL_RR; - else // all rr - new_state = DRAW_ALL_RR; - - //free dynamically allocated pointers - g_free(combo_box_content); - - draw_state->reset_nets_congestion_and_rr(); - draw_state->draw_rr_toggle = new_state; - - application.update_message(draw_state->default_message); - application.refresh_drawing(); + /* this is the callback function for runtime created toggle_rr button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_rr"; + auto toggle_rr = find_button(button_name.c_str()); + + enum e_draw_rr_toggle new_state; + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_rr)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_RR; + else if (strcmp(combo_box_content, "Nodes") == 0) + new_state = DRAW_NODES_RR; + else if (strcmp(combo_box_content, "Nodes SBox") == 0) + new_state = DRAW_NODES_SBOX_RR; + else if (strcmp(combo_box_content, "Nodes SBox CBox") == 0) + new_state = DRAW_NODES_SBOX_CBOX_RR; + else if (strcmp(combo_box_content, "Nodes SBox CBox Internal") == 0) + new_state = DRAW_NODES_SBOX_CBOX_INTERNAL_RR; + else + // all rr + new_state = DRAW_ALL_RR; + + //free dynamically allocated pointers + g_free(combo_box_content); + + draw_state->reset_nets_congestion_and_rr(); + draw_state->draw_rr_toggle = new_state; + + application.update_message(draw_state->default_message); + application.refresh_drawing(); } -void toggle_congestion(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_congestion button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_congestion"; - auto toggle_congestion = find_button(button_name.c_str()); - - enum e_draw_congestion new_state; - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_congestion)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_CONGEST; - else if (strcmp(combo_box_content, "Congested") == 0) - new_state = DRAW_CONGESTED; - else // congested with nets - new_state = DRAW_CONGESTED_WITH_NETS; - - draw_state->reset_nets_congestion_and_rr(); - draw_state->show_congestion = new_state; - if (draw_state->show_congestion == DRAW_NO_CONGEST) { - application.update_message(draw_state->default_message); - } - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_congestion(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_congestion button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_congestion"; + auto toggle_congestion = find_button(button_name.c_str()); + + enum e_draw_congestion new_state; + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_congestion)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_CONGEST; + else if (strcmp(combo_box_content, "Congested") == 0) + new_state = DRAW_CONGESTED; + else + // congested with nets + new_state = DRAW_CONGESTED_WITH_NETS; + + draw_state->reset_nets_congestion_and_rr(); + draw_state->show_congestion = new_state; + if (draw_state->show_congestion == DRAW_NO_CONGEST) { + application.update_message(draw_state->default_message); + } + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_routing_congestion_cost(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_routing_congestion_cost button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_routing_congestion_cost"; - auto toggle_routing_congestion_cost = find_button(button_name.c_str()); - enum e_draw_routing_costs new_state; - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_routing_congestion_cost)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Total Routing Costs") == 0) - new_state = DRAW_TOTAL_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Log Total Routing Costs") == 0) - new_state = DRAW_LOG_TOTAL_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Acc Routing Costs") == 0) - new_state = DRAW_ACC_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Log Acc Routing Costs") == 0) - new_state = DRAW_LOG_ACC_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Pres Routing Costs") == 0) - new_state = DRAW_PRES_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Log Pres Routing Costs") == 0) - new_state = DRAW_LOG_PRES_ROUTING_COSTS; - else - new_state = DRAW_BASE_ROUTING_COSTS; - - draw_state->reset_nets_congestion_and_rr(); - draw_state->show_routing_costs = new_state; - g_free(combo_box_content); - if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_routing_congestion_cost(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_routing_congestion_cost button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_routing_congestion_cost"; + auto toggle_routing_congestion_cost = find_button(button_name.c_str()); + enum e_draw_routing_costs new_state; + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_routing_congestion_cost)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Total Routing Costs") == 0) + new_state = DRAW_TOTAL_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Log Total Routing Costs") == 0) + new_state = DRAW_LOG_TOTAL_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Acc Routing Costs") == 0) + new_state = DRAW_ACC_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Log Acc Routing Costs") == 0) + new_state = DRAW_LOG_ACC_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Pres Routing Costs") == 0) + new_state = DRAW_PRES_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Log Pres Routing Costs") == 0) + new_state = DRAW_LOG_PRES_ROUTING_COSTS; + else + new_state = DRAW_BASE_ROUTING_COSTS; + + draw_state->reset_nets_congestion_and_rr(); + draw_state->show_routing_costs = new_state; + g_free(combo_box_content); + if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } -void toggle_routing_bounding_box(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_routing_bounding_box button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - auto& route_ctx = g_vpr_ctx.routing(); - // get the pointer to the toggle_routing_bounding_box button - std::string button_name = "toggle_routing_bounding_box"; - auto toggle_routing_bounding_box = find_button(button_name.c_str()); - - if (route_ctx.route_bb.size() == 0) - return; //Nothing to draw - - // use the pointer to get the active value - int new_value = gtk_spin_button_get_value_as_int((GtkSpinButton*)toggle_routing_bounding_box); - - // assign value to draw_state->show_routing_bb, bound check + set OPEN when it's -1 (draw nothing) - if (new_value < -1) - draw_state->show_routing_bb = -1; - else if (new_value == -1) - draw_state->show_routing_bb = OPEN; - else if (new_value >= (int)(route_ctx.route_bb.size())) - draw_state->show_routing_bb = route_ctx.route_bb.size() - 1; - else - draw_state->show_routing_bb = new_value; - - //redraw - if ((int)(draw_state->show_routing_bb) == (int)((int)(route_ctx.route_bb.size()) - 1)) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_routing_bounding_box(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_routing_bounding_box button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + auto &route_ctx = g_vpr_ctx.routing(); + // get the pointer to the toggle_routing_bounding_box button + std::string button_name = "toggle_routing_bounding_box"; + auto toggle_routing_bounding_box = find_button(button_name.c_str()); + + if (route_ctx.route_bb.size() == 0) + return; //Nothing to draw + + // use the pointer to get the active value + int new_value = gtk_spin_button_get_value_as_int( + (GtkSpinButton*) toggle_routing_bounding_box); + + // assign value to draw_state->show_routing_bb, bound check + set OPEN when it's -1 (draw nothing) + if (new_value < -1) + draw_state->show_routing_bb = -1; + else if (new_value == -1) + draw_state->show_routing_bb = OPEN; + else if (new_value >= (int) (route_ctx.route_bb.size())) + draw_state->show_routing_bb = route_ctx.route_bb.size() - 1; + else + draw_state->show_routing_bb = new_value; + + //redraw + if ((int) (draw_state->show_routing_bb) + == (int) ((int) (route_ctx.route_bb.size()) - 1)) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } -void toggle_routing_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_routing_util button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_routing_util"; - auto toggle_routing_util = find_button(button_name.c_str()); - - enum e_draw_routing_util new_state; - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_routing_util)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_ROUTING_UTIL; - else if (strcmp(combo_box_content, "Routing Util") == 0) - new_state = DRAW_ROUTING_UTIL; - else if (strcmp(combo_box_content, "Routing Util with Value") == 0) - new_state = DRAW_ROUTING_UTIL_WITH_VALUE; - else if (strcmp(combo_box_content, "Routing Util with Formula") == 0) - new_state = DRAW_ROUTING_UTIL_WITH_FORMULA; - else - new_state = DRAW_ROUTING_UTIL_OVER_BLOCKS; - - g_free(combo_box_content); - draw_state->show_routing_util = new_state; - - if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_routing_util(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_routing_util button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_routing_util"; + auto toggle_routing_util = find_button(button_name.c_str()); + + enum e_draw_routing_util new_state; + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_routing_util)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_ROUTING_UTIL; + else if (strcmp(combo_box_content, "Routing Util") == 0) + new_state = DRAW_ROUTING_UTIL; + else if (strcmp(combo_box_content, "Routing Util with Value") == 0) + new_state = DRAW_ROUTING_UTIL_WITH_VALUE; + else if (strcmp(combo_box_content, "Routing Util with Formula") == 0) + new_state = DRAW_ROUTING_UTIL_WITH_FORMULA; + else + new_state = DRAW_ROUTING_UTIL_OVER_BLOCKS; + + g_free(combo_box_content); + draw_state->show_routing_util = new_state; + + if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } -void toggle_blk_internal(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_blk_internal button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_blk_internal"; - auto toggle_blk_internal = find_button(button_name.c_str()); - - int new_value = gtk_spin_button_get_value_as_int((GtkSpinButton*)toggle_blk_internal); - 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; - else - draw_state->show_blk_internal = new_value; - application.refresh_drawing(); +void toggle_blk_internal(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_blk_internal button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_blk_internal"; + auto toggle_blk_internal = find_button(button_name.c_str()); + + int new_value = gtk_spin_button_get_value_as_int( + (GtkSpinButton*) toggle_blk_internal); + 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; + else + draw_state->show_blk_internal = new_value; + application.refresh_drawing(); } -void toggle_block_pin_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_block_pin_util button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_block_pin_util"; - auto toggle_block_pin_util = find_button(button_name.c_str()); - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_block_pin_util)); - if (strcmp(combo_box_content, "None") == 0) { - draw_state->show_blk_pin_util = DRAW_NO_BLOCK_PIN_UTIL; - draw_reset_blk_colors(); - application.update_message(draw_state->default_message); - } else if (strcmp(combo_box_content, "All") == 0) - draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_TOTAL; - else if (strcmp(combo_box_content, "Inputs") == 0) - draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_INPUTS; - else - draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_OUTPUTS; - - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_block_pin_util(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_block_pin_util button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_block_pin_util"; + auto toggle_block_pin_util = find_button(button_name.c_str()); + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_block_pin_util)); + if (strcmp(combo_box_content, "None") == 0) { + draw_state->show_blk_pin_util = DRAW_NO_BLOCK_PIN_UTIL; + draw_reset_blk_colors(); + application.update_message(draw_state->default_message); + } else if (strcmp(combo_box_content, "All") == 0) + draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_TOTAL; + else if (strcmp(combo_box_content, "Inputs") == 0) + draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_INPUTS; + else + draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_OUTPUTS; + + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_placement_macros(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_placement_macros button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_placement_macros"; - auto toggle_placement_macros = find_button(button_name.c_str()); - - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_placement_macros)); - if (strcmp(combo_box_content, "None") == 0) - draw_state->show_placement_macros = DRAW_NO_PLACEMENT_MACROS; - else - draw_state->show_placement_macros = DRAW_PLACEMENT_MACROS; - - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_placement_macros(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_placement_macros button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_placement_macros"; + auto toggle_placement_macros = find_button(button_name.c_str()); + + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_placement_macros)); + if (strcmp(combo_box_content, "None") == 0) + draw_state->show_placement_macros = DRAW_NO_PLACEMENT_MACROS; + else + draw_state->show_placement_macros = DRAW_PLACEMENT_MACROS; + + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_crit_path(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_crit_path button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_crit_path"; - auto toggle_crit_path = find_button(button_name.c_str()); - - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_crit_path)); - if (strcmp(combo_box_content, "None") == 0) { - draw_state->show_crit_path = DRAW_NO_CRIT_PATH; - } else if (strcmp(combo_box_content, "Crit Path Flylines") == 0) - draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES; - else if (strcmp(combo_box_content, "Crit Path Flylines Delays") == 0) - draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES_DELAYS; - else if (strcmp(combo_box_content, "Crit Path Routing") == 0) - draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING; - else // Crit Path Routing Delays - draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING_DELAYS; - - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_crit_path(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_crit_path button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_crit_path"; + auto toggle_crit_path = find_button(button_name.c_str()); + + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_crit_path)); + if (strcmp(combo_box_content, "None") == 0) { + draw_state->show_crit_path = DRAW_NO_CRIT_PATH; + } else if (strcmp(combo_box_content, "Crit Path Flylines") == 0) + draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES; + else if (strcmp(combo_box_content, "Crit Path Flylines Delays") == 0) + draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES_DELAYS; + else if (strcmp(combo_box_content, "Crit Path Routing") == 0) + draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING; + else + // Crit Path Routing Delays + draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING_DELAYS; + + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_router_expansion_costs button - * which is written in button.cpp */ - t_draw_state* draw_state = get_draw_state_vars(); - std::string button_name = "toggle_router_expansion_costs"; - auto toggle_router_expansion_costs = find_button(button_name.c_str()); - - e_draw_router_expansion_cost new_state; - gchar* combo_box_content = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(toggle_router_expansion_costs)); - if (strcmp(combo_box_content, "None") == 0) { - new_state = DRAW_NO_ROUTER_EXPANSION_COST; - } else if (strcmp(combo_box_content, "Total") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL; - } else if (strcmp(combo_box_content, "Known") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN; - } else if (strcmp(combo_box_content, "Expected") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED; - } else if (strcmp(combo_box_content, "Total (with edges)") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES; - } else if (strcmp(combo_box_content, "Known (with edges)") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES; - } else if (strcmp(combo_box_content, "Expected (with edges)") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES; - } else { - VPR_THROW(VPR_ERROR_DRAW, "Unrecognzied draw RR cost option"); - } - - g_free(combo_box_content); - draw_state->show_router_expansion_cost = new_state; - - if (draw_state->show_router_expansion_cost == DRAW_NO_ROUTER_EXPANSION_COST) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created toggle_router_expansion_costs button + * which is written in button.cpp */ + t_draw_state *draw_state = get_draw_state_vars(); + std::string button_name = "toggle_router_expansion_costs"; + auto toggle_router_expansion_costs = find_button(button_name.c_str()); + + e_draw_router_expansion_cost new_state; + gchar *combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_router_expansion_costs)); + if (strcmp(combo_box_content, "None") == 0) { + new_state = DRAW_NO_ROUTER_EXPANSION_COST; + } else if (strcmp(combo_box_content, "Total") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL; + } else if (strcmp(combo_box_content, "Known") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN; + } else if (strcmp(combo_box_content, "Expected") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED; + } else if (strcmp(combo_box_content, "Total (with edges)") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES; + } else if (strcmp(combo_box_content, "Known (with edges)") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES; + } else if (strcmp(combo_box_content, "Expected (with edges)") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES; + } else { + VPR_THROW(VPR_ERROR_DRAW, "Unrecognzied draw RR cost option"); + } + + g_free(combo_box_content); + draw_state->show_router_expansion_cost = new_state; + + if (draw_state->show_router_expansion_cost + == DRAW_NO_ROUTER_EXPANSION_COST) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } #endif // NO_GRAPHICS -void alloc_draw_structs(const t_arch* arch) { +void alloc_draw_structs(const t_arch *arch) { #ifndef NO_GRAPHICS - /* Call accessor functions to retrieve global variables. */ - t_draw_coords* draw_coords = get_draw_coords_vars(); - t_draw_state* draw_state = get_draw_state_vars(); - auto& device_ctx = g_vpr_ctx.device(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - - /* Allocate the structures needed to draw the placement and routing-> Set * - * up the default colors for blocks and nets. */ - draw_coords->tile_x = (float*)vtr::malloc(device_ctx.grid.width() * sizeof(float)); - draw_coords->tile_y = (float*)vtr::malloc(device_ctx.grid.height() * sizeof(float)); - - /* For sub-block drawings inside clbs */ - draw_internal_alloc_blk(); - - draw_state->net_color.resize(cluster_ctx.clb_nlist.nets().size()); - draw_state->block_color_.resize(cluster_ctx.clb_nlist.blocks().size()); - draw_state->use_default_block_color_.resize(cluster_ctx.clb_nlist.blocks().size()); - - /* Space is allocated for draw_rr_node but not initialized because we do * - * not yet know information about the routing resources. */ - draw_state->draw_rr_node = (t_draw_rr_node*)vtr::malloc( - device_ctx.rr_nodes.size() * sizeof(t_draw_rr_node)); - - draw_state->arch_info = arch; - - deselect_all(); /* Set initial colors */ + /* Call accessor functions to retrieve global variables. */ + t_draw_coords *draw_coords = get_draw_coords_vars(); + t_draw_state *draw_state = get_draw_state_vars(); + auto &device_ctx = g_vpr_ctx.device(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + + /* Allocate the structures needed to draw the placement and routing-> Set * + * up the default colors for blocks and nets. */ + draw_coords->tile_x = (float*) vtr::malloc( + device_ctx.grid.width() * sizeof(float)); + draw_coords->tile_y = (float*) vtr::malloc( + device_ctx.grid.height() * sizeof(float)); + + /* For sub-block drawings inside clbs */ + draw_internal_alloc_blk(); + + draw_state->net_color.resize(cluster_ctx.clb_nlist.nets().size()); + draw_state->block_color_.resize(cluster_ctx.clb_nlist.blocks().size()); + draw_state->use_default_block_color_.resize( + cluster_ctx.clb_nlist.blocks().size()); + + /* Space is allocated for draw_rr_node but not initialized because we do * + * not yet know information about the routing resources. */ + draw_state->draw_rr_node = (t_draw_rr_node*) vtr::malloc( + device_ctx.rr_nodes.size() * sizeof(t_draw_rr_node)); + + draw_state->arch_info = arch; + + deselect_all(); /* Set initial colors */ #else (void)arch; #endif // NO_GRAPHICS @@ -881,25 +973,25 @@ void alloc_draw_structs(const t_arch* arch) { void free_draw_structs() { #ifndef NO_GRAPHICS - /* Free everything allocated by alloc_draw_structs. Called after close_graphics() * - * in vpr_api.c. - * - * For safety, set all the array pointers to NULL in case any data - * structure gets freed twice. */ - t_draw_state* draw_state = get_draw_state_vars(); - t_draw_coords* draw_coords = get_draw_coords_vars(); - - if (draw_coords != nullptr) { - free(draw_coords->tile_x); - draw_coords->tile_x = nullptr; - free(draw_coords->tile_y); - draw_coords->tile_y = nullptr; - } - - if (draw_state != nullptr) { - free(draw_state->draw_rr_node); - draw_state->draw_rr_node = nullptr; - } + /* Free everything allocated by alloc_draw_structs. Called after close_graphics() * + * in vpr_api.c. + * + * For safety, set all the array pointers to NULL in case any data + * structure gets freed twice. */ + t_draw_state *draw_state = get_draw_state_vars(); + t_draw_coords *draw_coords = get_draw_coords_vars(); + + if (draw_coords != nullptr) { + free(draw_coords->tile_x); + draw_coords->tile_x = nullptr; + free(draw_coords->tile_y); + draw_coords->tile_y = nullptr; + } + + if (draw_state != nullptr) { + free(draw_state->draw_rr_node); + draw_state->draw_rr_node = nullptr; + } #else ; #endif /* NO_GRAPHICS */ @@ -907,58 +999,68 @@ void free_draw_structs() { void init_draw_coords(float width_val) { #ifndef NO_GRAPHICS - /* Load the arrays containing the left and bottom coordinates of the clbs * - * forming the FPGA. tile_width_val sets the width and height of a drawn * - * clb. */ - 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(); - - if (!draw_state->show_graphics && !draw_state->save_graphics && draw_state->graphics_commands.empty()) - return; //do not initialize only if --disp off and --save_graphics off - /* Each time routing is on screen, need to reallocate the color of each * - * rr_node, as the number of rr_nodes may change. */ - if (device_ctx.rr_nodes.size() != 0) { - draw_state->draw_rr_node = (t_draw_rr_node*)vtr::realloc(draw_state->draw_rr_node, - (device_ctx.rr_nodes.size()) * sizeof(t_draw_rr_node)); - for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { - draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[i].node_highlighted = false; - } - } - draw_coords->tile_width = width_val; - draw_coords->pin_size = 0.3; - for (const auto& type : device_ctx.physical_tile_types) { - auto num_pins = type.num_pins; - if (num_pins > 0) { - draw_coords->pin_size = std::min(draw_coords->pin_size, - (draw_coords->get_tile_width() / (4.0F * num_pins))); - } - } - - size_t j = 0; - for (size_t i = 0; i < (device_ctx.grid.width() - 1); i++) { - draw_coords->tile_x[i] = (i * draw_coords->get_tile_width()) + j; - j += device_ctx.chan_width.y_list[i] + 1; /* N wires need N+1 units of space */ - } - draw_coords->tile_x[device_ctx.grid.width() - 1] = ((device_ctx.grid.width() - 1) * draw_coords->get_tile_width()) + j; - j = 0; - for (size_t i = 0; i < (device_ctx.grid.height() - 1); ++i) { - draw_coords->tile_y[i] = (i * draw_coords->get_tile_width()) + j; - j += device_ctx.chan_width.x_list[i] + 1; - } - draw_coords->tile_y[device_ctx.grid.height() - 1] = ((device_ctx.grid.height() - 1) * draw_coords->get_tile_width()) + j; - /* Load coordinates of sub-blocks inside the clbs */ - draw_internal_init_blk(); - //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 - constexpr float VISIBLE_MARGIN = 0.01; - - float draw_width = draw_coords->tile_x[device_ctx.grid.width() - 1] + draw_coords->get_tile_width(); - float draw_height = draw_coords->tile_y[device_ctx.grid.height() - 1] + draw_coords->get_tile_width(); - - initial_world = ezgl::rectangle({-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height}, {(1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN) * draw_height}); + /* Load the arrays containing the left and bottom coordinates of the clbs * + * forming the FPGA. tile_width_val sets the width and height of a drawn * + * clb. */ + 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(); + + if (!draw_state->show_graphics && !draw_state->save_graphics + && draw_state->graphics_commands.empty()) + return; //do not initialize only if --disp off and --save_graphics off + /* Each time routing is on screen, need to reallocate the color of each * + * rr_node, as the number of rr_nodes may change. */ + if (device_ctx.rr_nodes.size() != 0) { + draw_state->draw_rr_node = (t_draw_rr_node*) vtr::realloc( + draw_state->draw_rr_node, + (device_ctx.rr_nodes.size()) * sizeof(t_draw_rr_node)); + for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { + draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[i].node_highlighted = false; + } + } + draw_coords->tile_width = width_val; + draw_coords->pin_size = 0.3; + for (const auto &type : device_ctx.physical_tile_types) { + auto num_pins = type.num_pins; + if (num_pins > 0) { + draw_coords->pin_size = std::min(draw_coords->pin_size, + (draw_coords->get_tile_width() / (4.0F * num_pins))); + } + } + + size_t j = 0; + for (size_t i = 0; i < (device_ctx.grid.width() - 1); i++) { + draw_coords->tile_x[i] = (i * draw_coords->get_tile_width()) + j; + j += device_ctx.chan_width.y_list[i] + 1; /* N wires need N+1 units of space */ + } + draw_coords->tile_x[device_ctx.grid.width() - 1] = ((device_ctx.grid.width() + - 1) * draw_coords->get_tile_width()) + j; + j = 0; + for (size_t i = 0; i < (device_ctx.grid.height() - 1); ++i) { + draw_coords->tile_y[i] = (i * draw_coords->get_tile_width()) + j; + j += device_ctx.chan_width.x_list[i] + 1; + } + draw_coords->tile_y[device_ctx.grid.height() - 1] = + ((device_ctx.grid.height() - 1) * draw_coords->get_tile_width()) + + j; + /* Load coordinates of sub-blocks inside the clbs */ + draw_internal_init_blk(); + //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 + constexpr float VISIBLE_MARGIN = 0.01; + + float draw_width = draw_coords->tile_x[device_ctx.grid.width() - 1] + + draw_coords->get_tile_width(); + float draw_height = draw_coords->tile_y[device_ctx.grid.height() - 1] + + draw_coords->get_tile_width(); + + initial_world = ezgl::rectangle( + { -VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height }, + { (1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN) + * draw_height }); #else (void)width_val; #endif /* NO_GRAPHICS */ @@ -968,1074 +1070,1173 @@ void init_draw_coords(float width_val) { /* Draws the blocks placed on the proper clbs. Occupied blocks are darker colours * * while empty ones are lighter colours and have a dashed border. */ -static void drawplace(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(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.placement(); - - ClusterBlockId bnum; - int num_sub_tiles; - - g->set_line_width(0); - for (size_t i = 0; i < device_ctx.grid.width(); i++) { - for (size_t j = 0; j < device_ctx.grid.height(); j++) { - /* Only the first block of a group should control drawing */ - if (device_ctx.grid[i][j].width_offset > 0 || device_ctx.grid[i][j].height_offset > 0) - continue; - - num_sub_tiles = device_ctx.grid[i][j].type->capacity; - /* Don't draw if tile capacity is zero. eg-> corners. */ - if (num_sub_tiles == 0) { - continue; - } - - for (int k = 0; k < num_sub_tiles; ++k) { - /* Look at the tile at start of large block */ - bnum = place_ctx.grid_blocks[i][j].blocks[k]; - /* Fill background for the clb. Do not fill if "show_blk_internal" - * is toggled. - */ - if (bnum == INVALID_BLOCK_ID) - continue; - - //Determine the block color and logical type - ezgl::color block_color; - t_logical_block_type_ptr logical_block_type = nullptr; - - //flag whether the current location is highlighted with a special color or not - bool current_loc_is_highlighted = false; - - if (placer_breakpoint_reached()) - current_loc_is_highlighted = highlight_loc_with_specific_color(int(i), int(j), block_color); - - // No color specified at this location; use the block color. - if (current_loc_is_highlighted == false) { - if (bnum != EMPTY_BLOCK_ID) { - block_color = draw_state->block_color(bnum); - } else { - block_color = get_block_type_color(device_ctx.grid[i][j].type); - block_color = lighten_color(block_color, EMPTY_BLOCK_LIGHTEN_FACTOR); - } - } - - auto tile_type = device_ctx.grid[i][j].type; - logical_block_type = pick_logical_type(tile_type); - - g->set_color(block_color); - /* Get coords of current sub_tile */ - ezgl::rectangle abs_clb_bbox = draw_coords->get_absolute_clb_bbox(i, j, k, logical_block_type); - ezgl::point2d center = abs_clb_bbox.center(); - - g->fill_rectangle(abs_clb_bbox); - - g->set_color(ezgl::BLACK); - - g->set_line_dash((EMPTY_BLOCK_ID == bnum) ? ezgl::line_dash::asymmetric_5_3 : ezgl::line_dash::none); - if (draw_state->draw_block_outlines) { - g->draw_rectangle(abs_clb_bbox); - } - - if (draw_state->draw_block_text) { - /* Draw text if the space has parts of the netlist */ - if (bnum != EMPTY_BLOCK_ID && bnum != INVALID_BLOCK_ID) { - std::string name = cluster_ctx.clb_nlist.block_name(bnum) + vtr::string_fmt(" (#%zu)", size_t(bnum)); - - g->draw_text(center, name.c_str(), abs_clb_bbox.width(), abs_clb_bbox.height()); - } - /* Draw text for block type so that user knows what block */ - if (device_ctx.grid[i][j].width_offset == 0 && device_ctx.grid[i][j].height_offset == 0) { - std::string block_type_loc = device_ctx.grid[i][j].type->name; - block_type_loc += vtr::string_fmt(" (%d,%d)", i, j); - - g->draw_text(center - ezgl::point2d(0, abs_clb_bbox.height() / 4), - block_type_loc.c_str(), abs_clb_bbox.width(), abs_clb_bbox.height()); - } - } - } - } - } +static void drawplace(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(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_ctx = g_vpr_ctx.placement(); + + ClusterBlockId bnum; + int num_sub_tiles; + + g->set_line_width(0); + for (size_t i = 0; i < device_ctx.grid.width(); i++) { + for (size_t j = 0; j < device_ctx.grid.height(); j++) { + /* Only the first block of a group should control drawing */ + if (device_ctx.grid[i][j].width_offset > 0 + || device_ctx.grid[i][j].height_offset > 0) + continue; + + num_sub_tiles = device_ctx.grid[i][j].type->capacity; + /* Don't draw if tile capacity is zero. eg-> corners. */ + if (num_sub_tiles == 0) { + continue; + } + + for (int k = 0; k < num_sub_tiles; ++k) { + /* Look at the tile at start of large block */ + bnum = place_ctx.grid_blocks[i][j].blocks[k]; + /* Fill background for the clb. Do not fill if "show_blk_internal" + * is toggled. + */ + if (bnum == INVALID_BLOCK_ID) + continue; + + //Determine the block color and logical type + ezgl::color block_color; + t_logical_block_type_ptr logical_block_type = nullptr; + + //flag whether the current location is highlighted with a special color or not + bool current_loc_is_highlighted = false; + + if (placer_breakpoint_reached()) + current_loc_is_highlighted = + highlight_loc_with_specific_color(int(i), int(j), + block_color); + + // No color specified at this location; use the block color. + if (current_loc_is_highlighted == false) { + if (bnum != EMPTY_BLOCK_ID) { + block_color = draw_state->block_color(bnum); + } else { + block_color = get_block_type_color( + device_ctx.grid[i][j].type); + block_color = lighten_color(block_color, + EMPTY_BLOCK_LIGHTEN_FACTOR); + } + } + + auto tile_type = device_ctx.grid[i][j].type; + logical_block_type = pick_logical_type(tile_type); + + g->set_color(block_color); + /* Get coords of current sub_tile */ + ezgl::rectangle abs_clb_bbox = + draw_coords->get_absolute_clb_bbox(i, j, k, + logical_block_type); + ezgl::point2d center = abs_clb_bbox.center(); + + g->fill_rectangle(abs_clb_bbox); + + g->set_color(ezgl::BLACK); + + g->set_line_dash( + (EMPTY_BLOCK_ID == bnum) ? + ezgl::line_dash::asymmetric_5_3 : + ezgl::line_dash::none); + if (draw_state->draw_block_outlines) { + g->draw_rectangle(abs_clb_bbox); + } + + if (draw_state->draw_block_text) { + /* Draw text if the space has parts of the netlist */ + if (bnum != EMPTY_BLOCK_ID && bnum != INVALID_BLOCK_ID) { + std::string name = cluster_ctx.clb_nlist.block_name( + bnum) + + vtr::string_fmt(" (#%zu)", size_t(bnum)); + + g->draw_text(center, name.c_str(), abs_clb_bbox.width(), + abs_clb_bbox.height()); + } + /* Draw text for block type so that user knows what block */ + if (device_ctx.grid[i][j].width_offset == 0 + && device_ctx.grid[i][j].height_offset == 0) { + std::string block_type_loc = + device_ctx.grid[i][j].type->name; + block_type_loc += vtr::string_fmt(" (%d,%d)", i, j); + + g->draw_text( + center + - ezgl::point2d(0, + abs_clb_bbox.height() / 4), + block_type_loc.c_str(), abs_clb_bbox.width(), + abs_clb_bbox.height()); + } + } + } + } + } } -static void drawnets(ezgl::renderer* g) { - t_draw_state* draw_state = get_draw_state_vars(); - t_draw_coords* draw_coords = get_draw_coords_vars(); - /* 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. */ - - ClusterBlockId b1, b2; - auto& cluster_ctx = g_vpr_ctx.clustering(); - - float NET_ALPHA = draw_state->net_alpha; - - g->set_line_dash(ezgl::line_dash::none); - g->set_line_width(0); - - /* Draw the net as a star from the source to each sink. Draw from centers of * - * blocks (or sub blocks in the case of IOs). */ - - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) - continue; /* Don't draw */ - - g->set_color(draw_state->net_color[net_id], draw_state->net_color[net_id].alpha * NET_ALPHA); - b1 = cluster_ctx.clb_nlist.net_driver_block(net_id); - ezgl::point2d driver_center = draw_coords->get_absolute_clb_bbox(b1, cluster_ctx.clb_nlist.block_type(b1)).center(); - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - b2 = cluster_ctx.clb_nlist.pin_block(pin_id); - ezgl::point2d sink_center = draw_coords->get_absolute_clb_bbox(b2, cluster_ctx.clb_nlist.block_type(b2)).center(); - g->draw_line(driver_center, sink_center); - /* Uncomment to draw a chain instead of a star. */ - /* driver_center = sink_center; */ - } - } +static void drawnets(ezgl::renderer *g) { + t_draw_state *draw_state = get_draw_state_vars(); + t_draw_coords *draw_coords = get_draw_coords_vars(); + /* 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. */ + + ClusterBlockId b1, b2; + auto &cluster_ctx = g_vpr_ctx.clustering(); + + float NET_ALPHA = draw_state->net_alpha; + + g->set_line_dash(ezgl::line_dash::none); + g->set_line_width(0); + + /* Draw the net as a star from the source to each sink. Draw from centers of * + * blocks (or sub blocks in the case of IOs). */ + + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + continue; /* Don't draw */ + + g->set_color(draw_state->net_color[net_id], + draw_state->net_color[net_id].alpha * NET_ALPHA); + b1 = cluster_ctx.clb_nlist.net_driver_block(net_id); + ezgl::point2d driver_center = draw_coords->get_absolute_clb_bbox(b1, + cluster_ctx.clb_nlist.block_type(b1)).center(); + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + b2 = cluster_ctx.clb_nlist.pin_block(pin_id); + ezgl::point2d sink_center = draw_coords->get_absolute_clb_bbox(b2, + cluster_ctx.clb_nlist.block_type(b2)).center(); + g->draw_line(driver_center, sink_center); + /* Uncomment to draw a chain instead of a star. */ + /* driver_center = sink_center; */ + } + } } -static void draw_congestion(ezgl::renderer* g) { - /* Draws all the overused routing resources (i.e. congestion) in various contrasting colors showing congestion ratio. */ - t_draw_state* draw_state = get_draw_state_vars(); - - if (draw_state->show_congestion == DRAW_NO_CONGEST) { - return; - } - - auto& device_ctx = g_vpr_ctx.device(); - auto& route_ctx = g_vpr_ctx.routing(); - - //Record min/max congestion - float min_congestion_ratio = 1.; - float max_congestion_ratio = min_congestion_ratio; - std::vector congested_rr_nodes = collect_congested_rr_nodes(); - for (int inode : congested_rr_nodes) { - short occ = route_ctx.rr_node_route_inf[inode].occ(); - short capacity = device_ctx.rr_nodes[inode].capacity(); - - float congestion_ratio = float(occ) / capacity; - - max_congestion_ratio = std::max(max_congestion_ratio, congestion_ratio); - } - - char msg[vtr::bufsize]; - if (draw_state->show_congestion == DRAW_CONGESTED) { - sprintf(msg, "RR Node Overuse ratio range (%.2f, %.2f]", min_congestion_ratio, max_congestion_ratio); - } else { - VTR_ASSERT(draw_state->show_congestion == DRAW_CONGESTED_WITH_NETS); - sprintf(msg, "RR Node Overuse ratio range (%.2f, %.2f] (and congested nets)", min_congestion_ratio, max_congestion_ratio); - } - application.update_message(msg); - - std::shared_ptr cmap = std::make_shared(min_congestion_ratio, max_congestion_ratio); - - //Sort the nodes in ascending order of value for drawing, this ensures high - //valued nodes are not overdrawn by lower value ones (e.g-> when zoomed-out far) - auto cmp_ascending_acc_cost = [&](int lhs_node, int rhs_node) { - short lhs_occ = route_ctx.rr_node_route_inf[lhs_node].occ(); - short lhs_capacity = device_ctx.rr_nodes[lhs_node].capacity(); - - short rhs_occ = route_ctx.rr_node_route_inf[rhs_node].occ(); - short rhs_capacity = device_ctx.rr_nodes[rhs_node].capacity(); - - float lhs_cong_ratio = float(lhs_occ) / lhs_capacity; - float rhs_cong_ratio = float(rhs_occ) / rhs_capacity; - - return lhs_cong_ratio < rhs_cong_ratio; - }; - std::sort(congested_rr_nodes.begin(), congested_rr_nodes.end(), cmp_ascending_acc_cost); - - if (draw_state->show_congestion == DRAW_CONGESTED_WITH_NETS) { - auto rr_node_nets = collect_rr_node_nets(); - - for (int inode : congested_rr_nodes) { - for (ClusterNetId net : rr_node_nets[inode]) { - ezgl::color color = kelly_max_contrast_colors[size_t(net) % kelly_max_contrast_colors.size()]; - draw_state->net_color[net] = color; - } - } - g->set_line_width(0); - drawroute(HIGHLIGHTED, g); - - //Reset colors - for (int inode : congested_rr_nodes) { - for (ClusterNetId net : rr_node_nets[inode]) { - draw_state->net_color[net] = DEFAULT_RR_NODE_COLOR; - } - } - } else { - g->set_line_width(2); - } - - //Draw each congested node - for (int inode : congested_rr_nodes) { - short occ = route_ctx.rr_node_route_inf[inode].occ(); - short capacity = device_ctx.rr_nodes[inode].capacity(); - - float congestion_ratio = float(occ) / capacity; - - bool node_congested = (occ > capacity); - VTR_ASSERT(node_congested); - - ezgl::color color = to_ezgl_color(cmap->color(congestion_ratio)); - - switch (device_ctx.rr_nodes[inode].type()) { - case CHANX: //fallthrough - case CHANY: - draw_rr_chan(inode, color, g); - break; - - case IPIN: //fallthrough - case OPIN: - draw_rr_pin(inode, color, g); - break; - default: - break; - } - } - - draw_state->color_map = std::move(cmap); +static void draw_congestion(ezgl::renderer *g) { + /* Draws all the overused routing resources (i.e. congestion) in various contrasting colors showing congestion ratio. */ + t_draw_state *draw_state = get_draw_state_vars(); + + if (draw_state->show_congestion == DRAW_NO_CONGEST) { + return; + } + + auto &device_ctx = g_vpr_ctx.device(); + auto &route_ctx = g_vpr_ctx.routing(); + + //Record min/max congestion + float min_congestion_ratio = 1.; + float max_congestion_ratio = min_congestion_ratio; + std::vector congested_rr_nodes = collect_congested_rr_nodes(); + for (int inode : congested_rr_nodes) { + short occ = route_ctx.rr_node_route_inf[inode].occ(); + short capacity = device_ctx.rr_nodes[inode].capacity(); + + float congestion_ratio = float(occ) / capacity; + + max_congestion_ratio = std::max(max_congestion_ratio, congestion_ratio); + } + + char msg[vtr::bufsize]; + if (draw_state->show_congestion == DRAW_CONGESTED) { + sprintf(msg, "RR Node Overuse ratio range (%.2f, %.2f]", + min_congestion_ratio, max_congestion_ratio); + } else { + VTR_ASSERT(draw_state->show_congestion == DRAW_CONGESTED_WITH_NETS); + sprintf(msg, + "RR Node Overuse ratio range (%.2f, %.2f] (and congested nets)", + min_congestion_ratio, max_congestion_ratio); + } + application.update_message(msg); + + std::shared_ptr cmap = std::make_shared( + min_congestion_ratio, max_congestion_ratio); + + //Sort the nodes in ascending order of value for drawing, this ensures high + //valued nodes are not overdrawn by lower value ones (e.g-> when zoomed-out far) + auto cmp_ascending_acc_cost = [&](int lhs_node, int rhs_node) { + short lhs_occ = route_ctx.rr_node_route_inf[lhs_node].occ(); + short lhs_capacity = device_ctx.rr_nodes[lhs_node].capacity(); + + short rhs_occ = route_ctx.rr_node_route_inf[rhs_node].occ(); + short rhs_capacity = device_ctx.rr_nodes[rhs_node].capacity(); + + float lhs_cong_ratio = float(lhs_occ) / lhs_capacity; + float rhs_cong_ratio = float(rhs_occ) / rhs_capacity; + + return lhs_cong_ratio < rhs_cong_ratio; + }; + std::sort(congested_rr_nodes.begin(), congested_rr_nodes.end(), + cmp_ascending_acc_cost); + + if (draw_state->show_congestion == DRAW_CONGESTED_WITH_NETS) { + auto rr_node_nets = collect_rr_node_nets(); + + for (int inode : congested_rr_nodes) { + for (ClusterNetId net : rr_node_nets[inode]) { + ezgl::color color = kelly_max_contrast_colors[size_t(net) + % kelly_max_contrast_colors.size()]; + draw_state->net_color[net] = color; + } + } + g->set_line_width(0); + drawroute(HIGHLIGHTED, g); + + //Reset colors + for (int inode : congested_rr_nodes) { + for (ClusterNetId net : rr_node_nets[inode]) { + draw_state->net_color[net] = DEFAULT_RR_NODE_COLOR; + } + } + } else { + g->set_line_width(2); + } + + //Draw each congested node + for (int inode : congested_rr_nodes) { + short occ = route_ctx.rr_node_route_inf[inode].occ(); + short capacity = device_ctx.rr_nodes[inode].capacity(); + + float congestion_ratio = float(occ) / capacity; + + bool node_congested = (occ > capacity); + VTR_ASSERT(node_congested); + + ezgl::color color = to_ezgl_color(cmap->color(congestion_ratio)); + + switch (device_ctx.rr_nodes[inode].type()) { + case CHANX: //fallthrough + case CHANY: + draw_rr_chan(inode, color, g); + break; + + case IPIN: //fallthrough + case OPIN: + draw_rr_pin(inode, color, g); + break; + default: + break; + } + } + + draw_state->color_map = std::move(cmap); } -static void draw_routing_costs(ezgl::renderer* g) { - /* Draws routing resource nodes colored according to their congestion costs */ - - t_draw_state* draw_state = get_draw_state_vars(); - - /* show_routing_costs controls whether the total/sum of the costs or individual - * cost components (base cost, accumulated cost, present cost) are shown, and - * whether colours are proportional to the node's cost or the logarithm of - * it's cost.*/ - if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { - return; - } - - auto& device_ctx = g_vpr_ctx.device(); - auto& route_ctx = g_vpr_ctx.routing(); - g->set_line_width(0); - - VTR_ASSERT(!route_ctx.rr_node_route_inf.empty()); - - float min_cost = std::numeric_limits::infinity(); - float max_cost = -min_cost; - std::vector rr_node_costs(device_ctx.rr_nodes.size(), 0.); - - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - float cost = 0.; - if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS - || draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS) { - cost = get_single_rr_cong_cost(inode, get_draw_state_vars()->pres_fac); - - } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { - cost = get_single_rr_cong_base_cost(inode); - - } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS - || draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS) { - cost = get_single_rr_cong_acc_cost(inode); - - } else { - VTR_ASSERT(draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS - || draw_state->show_routing_costs == DRAW_LOG_PRES_ROUTING_COSTS); - cost = get_single_rr_cong_pres_cost(inode, get_draw_state_vars()->pres_fac); - } - - if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS - || draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS - || draw_state->show_routing_costs == DRAW_LOG_PRES_ROUTING_COSTS) { - cost = std::log(cost); - } - rr_node_costs[inode] = cost; - min_cost = std::min(min_cost, cost); - max_cost = std::max(max_cost, cost); - } - - //Hide min value, draw_rr_costs() ignores NaN's - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - if (rr_node_costs[inode] == min_cost) { - rr_node_costs[inode] = NAN; - } - } - char msg[vtr::bufsize]; - if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS) { - sprintf(msg, "Total Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS) { - sprintf(msg, "Log Total Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { - sprintf(msg, "Base Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS) { - sprintf(msg, "Accumulated (Historical) Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS) { - sprintf(msg, "Log Accumulated (Historical) Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS) { - sprintf(msg, "Present Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_LOG_PRES_ROUTING_COSTS) { - sprintf(msg, "Log Present Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else { - sprintf(msg, "Cost Range [%g, %g]", min_cost, max_cost); - } - application.update_message(msg); - - draw_rr_costs(g, rr_node_costs, true); +static void draw_routing_costs(ezgl::renderer *g) { + /* Draws routing resource nodes colored according to their congestion costs */ + + t_draw_state *draw_state = get_draw_state_vars(); + + /* show_routing_costs controls whether the total/sum of the costs or individual + * cost components (base cost, accumulated cost, present cost) are shown, and + * whether colours are proportional to the node's cost or the logarithm of + * it's cost.*/ + if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { + return; + } + + auto &device_ctx = g_vpr_ctx.device(); + auto &route_ctx = g_vpr_ctx.routing(); + g->set_line_width(0); + + VTR_ASSERT(!route_ctx.rr_node_route_inf.empty()); + + float min_cost = std::numeric_limits::infinity(); + float max_cost = -min_cost; + std::vector rr_node_costs(device_ctx.rr_nodes.size(), 0.); + + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + float cost = 0.; + if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_TOTAL_ROUTING_COSTS) { + cost = get_single_rr_cong_cost(inode, + get_draw_state_vars()->pres_fac); + + } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { + cost = get_single_rr_cong_base_cost(inode); + + } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_ACC_ROUTING_COSTS) { + cost = get_single_rr_cong_acc_cost(inode); + + } else { + VTR_ASSERT( + draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_PRES_ROUTING_COSTS); + cost = get_single_rr_cong_pres_cost(inode, + get_draw_state_vars()->pres_fac); + } + + if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS + || draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_PRES_ROUTING_COSTS) { + cost = std::log(cost); + } + rr_node_costs[inode] = cost; + min_cost = std::min(min_cost, cost); + max_cost = std::max(max_cost, cost); + } + + //Hide min value, draw_rr_costs() ignores NaN's + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + if (rr_node_costs[inode] == min_cost) { + rr_node_costs[inode] = NAN; + } + } + char msg[vtr::bufsize]; + if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS) { + sprintf(msg, "Total Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS) { + sprintf(msg, "Log Total Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { + sprintf(msg, "Base Congestion Cost Range [%g, %g]", min_cost, max_cost); + } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS) { + sprintf(msg, "Accumulated (Historical) Congestion Cost Range [%g, %g]", + min_cost, max_cost); + } else if (draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS) { + sprintf(msg, + "Log Accumulated (Historical) Congestion Cost Range [%g, %g]", + min_cost, max_cost); + } else if (draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS) { + sprintf(msg, "Present Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else if (draw_state->show_routing_costs == DRAW_LOG_PRES_ROUTING_COSTS) { + sprintf(msg, "Log Present Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else { + sprintf(msg, "Cost Range [%g, %g]", min_cost, max_cost); + } + application.update_message(msg); + + draw_rr_costs(g, rr_node_costs, true); } -static void draw_routing_bb(ezgl::renderer* g) { - t_draw_state* draw_state = get_draw_state_vars(); - - if (draw_state->show_routing_bb == OPEN) { - return; - } - - auto& route_ctx = g_vpr_ctx.routing(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - - VTR_ASSERT(draw_state->show_routing_bb != OPEN); - VTR_ASSERT(draw_state->show_routing_bb < (int)route_ctx.route_bb.size()); - - t_draw_coords* draw_coords = get_draw_coords_vars(); - - auto net_id = ClusterNetId(draw_state->show_routing_bb); - const t_bb* bb = &route_ctx.route_bb[net_id]; - - //The router considers an RR node to be 'within' the the bounding box if it - //is *loosely* greater (i.e. greater than or equal) the left/bottom edges, and - //it is *loosely* less (i.e. less than or equal) the right/top edges. - // - //In the graphics we represent this by drawing the BB so that legal RR node start/end points - //are contained within the drawn box. Since VPR associates each x/y channel location to - //the right/top of the tile with the same x/y cordinates, this means we draw the box so that: - // * The left edge is to the left of the channel at bb xmin (including the channel at xmin) - // * The bottom edge is to the below of the channel at bb ymin (including the channel at ymin) - // * The right edge is to the right of the channel at bb xmax (including the channel at xmax) - // * The top edge is to the right of the channel at bb ymax (including the channel at ymax) - //Since tile_x/tile_y correspond to the drawing coordinates the block at grid x/y's bottom-left corner - //this means we need to shift the top/right drawn co-ordinate one tile + channel width right/up so - //the drawn box contains the top/right channels - double draw_xlow = draw_coords->tile_x[bb->xmin]; - double draw_ylow = draw_coords->tile_y[bb->ymin]; - double draw_xhigh = draw_coords->tile_x[bb->xmax] + 2 * draw_coords->get_tile_width(); - double draw_yhigh = draw_coords->tile_y[bb->ymax] + 2 * draw_coords->get_tile_height(); - - g->set_color(blk_RED); - g->draw_rectangle({draw_xlow, draw_ylow}, {draw_xhigh, draw_yhigh}); - - ezgl::color fill = blk_SKYBLUE; - fill.alpha *= 0.3; - g->set_color(fill); - g->fill_rectangle({draw_xlow, draw_ylow}, {draw_xhigh, draw_yhigh}); - - draw_routed_net(net_id, g); - - std::string msg; - msg += "Showing BB"; - msg += " (" + std::to_string(bb->xmin) + ", " + std::to_string(bb->ymin) + ", " + std::to_string(bb->xmax) + ", " + std::to_string(bb->ymax) + ")"; - msg += " and routing for net '" + cluster_ctx.clb_nlist.net_name(net_id) + "'"; - msg += " (#" + std::to_string(size_t(net_id)) + ")"; - application.update_message(msg.c_str()); +static void draw_routing_bb(ezgl::renderer *g) { + t_draw_state *draw_state = get_draw_state_vars(); + + if (draw_state->show_routing_bb == OPEN) { + return; + } + + auto &route_ctx = g_vpr_ctx.routing(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + + VTR_ASSERT(draw_state->show_routing_bb != OPEN); + VTR_ASSERT(draw_state->show_routing_bb < (int )route_ctx.route_bb.size()); + + t_draw_coords *draw_coords = get_draw_coords_vars(); + + auto net_id = ClusterNetId(draw_state->show_routing_bb); + const t_bb *bb = &route_ctx.route_bb[net_id]; + + //The router considers an RR node to be 'within' the the bounding box if it + //is *loosely* greater (i.e. greater than or equal) the left/bottom edges, and + //it is *loosely* less (i.e. less than or equal) the right/top edges. + // + //In the graphics we represent this by drawing the BB so that legal RR node start/end points + //are contained within the drawn box. Since VPR associates each x/y channel location to + //the right/top of the tile with the same x/y cordinates, this means we draw the box so that: + // * The left edge is to the left of the channel at bb xmin (including the channel at xmin) + // * The bottom edge is to the below of the channel at bb ymin (including the channel at ymin) + // * The right edge is to the right of the channel at bb xmax (including the channel at xmax) + // * The top edge is to the right of the channel at bb ymax (including the channel at ymax) + //Since tile_x/tile_y correspond to the drawing coordinates the block at grid x/y's bottom-left corner + //this means we need to shift the top/right drawn co-ordinate one tile + channel width right/up so + //the drawn box contains the top/right channels + double draw_xlow = draw_coords->tile_x[bb->xmin]; + double draw_ylow = draw_coords->tile_y[bb->ymin]; + double draw_xhigh = draw_coords->tile_x[bb->xmax] + + 2 * draw_coords->get_tile_width(); + double draw_yhigh = draw_coords->tile_y[bb->ymax] + + 2 * draw_coords->get_tile_height(); + + g->set_color(blk_RED); + g->draw_rectangle( { draw_xlow, draw_ylow }, { draw_xhigh, draw_yhigh }); + + ezgl::color fill = blk_SKYBLUE; + fill.alpha *= 0.3; + g->set_color(fill); + g->fill_rectangle( { draw_xlow, draw_ylow }, { draw_xhigh, draw_yhigh }); + + draw_routed_net(net_id, g); + + std::string msg; + msg += "Showing BB"; + msg += " (" + std::to_string(bb->xmin) + ", " + std::to_string(bb->ymin) + + ", " + std::to_string(bb->xmax) + ", " + std::to_string(bb->ymax) + + ")"; + msg += " and routing for net '" + cluster_ctx.clb_nlist.net_name(net_id) + + "'"; + msg += " (#" + std::to_string(size_t(net_id)) + ")"; + application.update_message(msg.c_str()); } -void draw_rr(ezgl::renderer* g) { - /* Draws the routing resources that exist in the FPGA, if the user wants * - * them drawn. */ - t_draw_state* draw_state = get_draw_state_vars(); - auto& device_ctx = g_vpr_ctx.device(); - - if (draw_state->draw_rr_toggle == DRAW_NO_RR) { - g->set_line_width(3); - drawroute(HIGHLIGHTED, g); - g->set_line_width(0); - return; - } - - g->set_line_dash(ezgl::line_dash::none); - - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - if (!draw_state->draw_rr_node[inode].node_highlighted) { - /* If not highlighted node, assign color based on type. */ - switch (device_ctx.rr_nodes[inode].type()) { - case CHANX: - case CHANY: - draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; - break; - case OPIN: - draw_state->draw_rr_node[inode].color = ezgl::PINK; - break; - case IPIN: - draw_state->draw_rr_node[inode].color = blk_LIGHTSKYBLUE; - break; - case SOURCE: - draw_state->draw_rr_node[inode].color = ezgl::PLUM; - break; - case SINK: - draw_state->draw_rr_node[inode].color = ezgl::DARK_SLATE_BLUE; - break; - default: - break; - } - } - - /* Now call drawing routines to draw the node. */ - switch (device_ctx.rr_nodes[inode].type()) { - case SINK: - draw_rr_src_sink(inode, draw_state->draw_rr_node[inode].color, g); - break; - case SOURCE: - draw_rr_edges(inode, g); - draw_rr_src_sink(inode, draw_state->draw_rr_node[inode].color, g); - break; - - case CHANX: - draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); - draw_rr_edges(inode, g); - break; - - case CHANY: - draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); - draw_rr_edges(inode, g); - break; - - case IPIN: - draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); - draw_rr_edges(inode, g); - break; - - case OPIN: - draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); - draw_rr_edges(inode, g); - break; - - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_rr: Unexpected rr_node type: %d.\n", device_ctx.rr_nodes[inode].type()); - } - } - - drawroute(HIGHLIGHTED, g); +void draw_rr(ezgl::renderer *g) { + /* Draws the routing resources that exist in the FPGA, if the user wants * + * them drawn. */ + t_draw_state *draw_state = get_draw_state_vars(); + auto &device_ctx = g_vpr_ctx.device(); + + if (draw_state->draw_rr_toggle == DRAW_NO_RR) { + g->set_line_width(3); + drawroute(HIGHLIGHTED, g); + g->set_line_width(0); + return; + } + + g->set_line_dash(ezgl::line_dash::none); + + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + if (!draw_state->draw_rr_node[inode].node_highlighted) { + /* If not highlighted node, assign color based on type. */ + switch (device_ctx.rr_nodes[inode].type()) { + case CHANX: + case CHANY: + draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; + break; + case OPIN: + draw_state->draw_rr_node[inode].color = ezgl::PINK; + break; + case IPIN: + draw_state->draw_rr_node[inode].color = blk_LIGHTSKYBLUE; + break; + case SOURCE: + draw_state->draw_rr_node[inode].color = ezgl::PLUM; + break; + case SINK: + draw_state->draw_rr_node[inode].color = ezgl::DARK_SLATE_BLUE; + break; + default: + break; + } + } + + /* Now call drawing routines to draw the node. */ + switch (device_ctx.rr_nodes[inode].type()) { + case SINK: + draw_rr_src_sink(inode, draw_state->draw_rr_node[inode].color, g); + break; + case SOURCE: + draw_rr_edges(inode, g); + draw_rr_src_sink(inode, draw_state->draw_rr_node[inode].color, g); + break; + + case CHANX: + draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); + draw_rr_edges(inode, g); + break; + + case CHANY: + draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); + draw_rr_edges(inode, g); + break; + + case IPIN: + draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); + draw_rr_edges(inode, g); + break; + + case OPIN: + draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); + draw_rr_edges(inode, g); + break; + + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_rr: Unexpected rr_node type: %d.\n", + device_ctx.rr_nodes[inode].type()); + } + } + + drawroute(HIGHLIGHTED, g); } -static void draw_rr_chan(int inode, const ezgl::color color, ezgl::renderer* g) { - auto& device_ctx = g_vpr_ctx.device(); - - t_rr_type type = device_ctx.rr_nodes[inode].type(); - - VTR_ASSERT(type == CHANX || type == CHANY); - - ezgl::rectangle bound_box = draw_get_rr_chan_bbox(inode); - e_direction dir = device_ctx.rr_nodes[inode].direction(); - - //We assume increasing direction, and swap if needed - ezgl::point2d start = bound_box.bottom_left(); - ezgl::point2d end = bound_box.top_right(); - if (dir == DEC_DIRECTION) { - std::swap(start, end); - } - - g->set_color(color); - if (color != DEFAULT_RR_NODE_COLOR) { - // If wire is highlighted, then draw with thicker linewidth. - g->set_line_width(3); - } - - g->draw_line(start, end); - - if (color != DEFAULT_RR_NODE_COLOR) { - // Revert width change - g->set_line_width(0); - } - - e_side mux_dir = TOP; - int coord_min = -1; - int coord_max = -1; - if (type == CHANX) { - coord_min = device_ctx.rr_nodes[inode].xlow(); - coord_max = device_ctx.rr_nodes[inode].xhigh(); - if (dir == INC_DIRECTION) { - mux_dir = RIGHT; - } else { - mux_dir = LEFT; - } - } else { - VTR_ASSERT(type == CHANY); - coord_min = device_ctx.rr_nodes[inode].ylow(); - coord_max = device_ctx.rr_nodes[inode].yhigh(); - if (dir == INC_DIRECTION) { - mux_dir = TOP; - } else { - mux_dir = BOTTOM; - } - } - - //Draw direction indicators at the boundary of each switch block, and label them - //with the corresponding switch point (see build_switchblocks.c for a description of switch points) - t_draw_coords* draw_coords = get_draw_coords_vars(); - float arrow_offset = DEFAULT_ARROW_SIZE / 2; - ezgl::color arrow_color = blk_LIGHTGREY; - ezgl::color text_color = ezgl::BLACK; - for (int k = coord_min; k <= coord_max; ++k) { - int switchpoint_min = -1; - int switchpoint_max = -1; - if (dir == INC_DIRECTION) { - switchpoint_min = k - coord_min; - switchpoint_max = switchpoint_min + 1; - } else { - switchpoint_min = (coord_max + 1) - k; - switchpoint_max = switchpoint_min - 1; - } - - ezgl::point2d arrow_loc_min(0, 0); - ezgl::point2d arrow_loc_max(0, 0); - if (type == CHANX) { - float sb_xmin = draw_coords->tile_x[k]; - arrow_loc_min = {sb_xmin + arrow_offset, start.y}; - - float sb_xmax = draw_coords->tile_x[k] + draw_coords->get_tile_width(); - arrow_loc_max = {sb_xmax - arrow_offset, start.y}; - - } else { - float sb_ymin = draw_coords->tile_y[k]; - arrow_loc_min = {start.x, sb_ymin + arrow_offset}; - - float sb_ymax = draw_coords->tile_y[k] + draw_coords->get_tile_height(); - arrow_loc_max = {start.x, sb_ymax - arrow_offset}; - } - - if (switchpoint_min == 0) { - if (dir != BI_DIRECTION) { - //Draw a mux at the start of each wire, labelled with it's size (#inputs) - draw_mux_with_size(start, mux_dir, WIRE_DRAWING_WIDTH, device_ctx.rr_nodes[inode].fan_in(), g); - } - } else { - //Draw arrows and label with switch point - if (k == coord_min) { - std::swap(arrow_color, text_color); - } - - g->set_color(arrow_color); - draw_triangle_along_line(g, arrow_loc_min, start, end); - - g->set_color(text_color); - ezgl::rectangle bbox(ezgl::point2d(arrow_loc_min.x - DEFAULT_ARROW_SIZE / 2, arrow_loc_min.y - DEFAULT_ARROW_SIZE / 4), - ezgl::point2d(arrow_loc_min.x + DEFAULT_ARROW_SIZE / 2, arrow_loc_min.y + DEFAULT_ARROW_SIZE / 4)); - ezgl::point2d center = bbox.center(); - g->draw_text(center, std::to_string(switchpoint_min), bbox.width(), bbox.height()); - - if (k == coord_min) { - //Revert - std::swap(arrow_color, text_color); - } - } - - if (switchpoint_max == 0) { - if (dir != BI_DIRECTION) { - //Draw a mux at the start of each wire, labelled with it's size (#inputs) - draw_mux_with_size(start, mux_dir, WIRE_DRAWING_WIDTH, device_ctx.rr_nodes[inode].fan_in(), g); - } - } else { - //Draw arrows and label with switch point - if (k == coord_max) { - std::swap(arrow_color, text_color); - } - - g->set_color(arrow_color); - draw_triangle_along_line(g, arrow_loc_max, start, end); - - g->set_color(text_color); - ezgl::rectangle bbox(ezgl::point2d(arrow_loc_max.x - DEFAULT_ARROW_SIZE / 2, arrow_loc_max.y - DEFAULT_ARROW_SIZE / 4), - ezgl::point2d(arrow_loc_max.x + DEFAULT_ARROW_SIZE / 2, arrow_loc_max.y + DEFAULT_ARROW_SIZE / 4)); - ezgl::point2d center = bbox.center(); - g->draw_text(center, std::to_string(switchpoint_max), bbox.width(), bbox.height()); - - if (k == coord_max) { - //Revert - std::swap(arrow_color, text_color); - } - } - } - g->set_color(color); //Ensure color is still set correctly if we drew any arrows/text +static void draw_rr_chan(int inode, const ezgl::color color, + ezgl::renderer *g) { + auto &device_ctx = g_vpr_ctx.device(); + + t_rr_type type = device_ctx.rr_nodes[inode].type(); + + VTR_ASSERT(type == CHANX || type == CHANY); + + ezgl::rectangle bound_box = draw_get_rr_chan_bbox(inode); + e_direction dir = device_ctx.rr_nodes[inode].direction(); + + //We assume increasing direction, and swap if needed + ezgl::point2d start = bound_box.bottom_left(); + ezgl::point2d end = bound_box.top_right(); + if (dir == DEC_DIRECTION) { + std::swap(start, end); + } + + g->set_color(color); + if (color != DEFAULT_RR_NODE_COLOR) { + // If wire is highlighted, then draw with thicker linewidth. + g->set_line_width(3); + } + + g->draw_line(start, end); + + if (color != DEFAULT_RR_NODE_COLOR) { + // Revert width change + g->set_line_width(0); + } + + e_side mux_dir = TOP; + int coord_min = -1; + int coord_max = -1; + if (type == CHANX) { + coord_min = device_ctx.rr_nodes[inode].xlow(); + coord_max = device_ctx.rr_nodes[inode].xhigh(); + if (dir == INC_DIRECTION) { + mux_dir = RIGHT; + } else { + mux_dir = LEFT; + } + } else { + VTR_ASSERT(type == CHANY); + coord_min = device_ctx.rr_nodes[inode].ylow(); + coord_max = device_ctx.rr_nodes[inode].yhigh(); + if (dir == INC_DIRECTION) { + mux_dir = TOP; + } else { + mux_dir = BOTTOM; + } + } + + //Draw direction indicators at the boundary of each switch block, and label them + //with the corresponding switch point (see build_switchblocks.c for a description of switch points) + t_draw_coords *draw_coords = get_draw_coords_vars(); + float arrow_offset = DEFAULT_ARROW_SIZE / 2; + ezgl::color arrow_color = blk_LIGHTGREY; + ezgl::color text_color = ezgl::BLACK; + for (int k = coord_min; k <= coord_max; ++k) { + int switchpoint_min = -1; + int switchpoint_max = -1; + if (dir == INC_DIRECTION) { + switchpoint_min = k - coord_min; + switchpoint_max = switchpoint_min + 1; + } else { + switchpoint_min = (coord_max + 1) - k; + switchpoint_max = switchpoint_min - 1; + } + + ezgl::point2d arrow_loc_min(0, 0); + ezgl::point2d arrow_loc_max(0, 0); + if (type == CHANX) { + float sb_xmin = draw_coords->tile_x[k]; + arrow_loc_min = { sb_xmin + arrow_offset, start.y }; + + float sb_xmax = draw_coords->tile_x[k] + + draw_coords->get_tile_width(); + arrow_loc_max = { sb_xmax - arrow_offset, start.y }; + + } else { + float sb_ymin = draw_coords->tile_y[k]; + arrow_loc_min = { start.x, sb_ymin + arrow_offset }; + + float sb_ymax = draw_coords->tile_y[k] + + draw_coords->get_tile_height(); + arrow_loc_max = { start.x, sb_ymax - arrow_offset }; + } + + if (switchpoint_min == 0) { + if (dir != BI_DIRECTION) { + //Draw a mux at the start of each wire, labelled with it's size (#inputs) + draw_mux_with_size(start, mux_dir, WIRE_DRAWING_WIDTH, + device_ctx.rr_nodes[inode].fan_in(), g); + } + } else { + //Draw arrows and label with switch point + if (k == coord_min) { + std::swap(arrow_color, text_color); + } + + g->set_color(arrow_color); + draw_triangle_along_line(g, arrow_loc_min, start, end); + + g->set_color(text_color); + ezgl::rectangle bbox( + ezgl::point2d(arrow_loc_min.x - DEFAULT_ARROW_SIZE / 2, + arrow_loc_min.y - DEFAULT_ARROW_SIZE / 4), + ezgl::point2d(arrow_loc_min.x + DEFAULT_ARROW_SIZE / 2, + arrow_loc_min.y + DEFAULT_ARROW_SIZE / 4)); + ezgl::point2d center = bbox.center(); + g->draw_text(center, std::to_string(switchpoint_min), bbox.width(), + bbox.height()); + + if (k == coord_min) { + //Revert + std::swap(arrow_color, text_color); + } + } + + if (switchpoint_max == 0) { + if (dir != BI_DIRECTION) { + //Draw a mux at the start of each wire, labelled with it's size (#inputs) + draw_mux_with_size(start, mux_dir, WIRE_DRAWING_WIDTH, + device_ctx.rr_nodes[inode].fan_in(), g); + } + } else { + //Draw arrows and label with switch point + if (k == coord_max) { + std::swap(arrow_color, text_color); + } + + g->set_color(arrow_color); + draw_triangle_along_line(g, arrow_loc_max, start, end); + + g->set_color(text_color); + ezgl::rectangle bbox( + ezgl::point2d(arrow_loc_max.x - DEFAULT_ARROW_SIZE / 2, + arrow_loc_max.y - DEFAULT_ARROW_SIZE / 4), + ezgl::point2d(arrow_loc_max.x + DEFAULT_ARROW_SIZE / 2, + arrow_loc_max.y + DEFAULT_ARROW_SIZE / 4)); + ezgl::point2d center = bbox.center(); + g->draw_text(center, std::to_string(switchpoint_max), bbox.width(), + bbox.height()); + + if (k == coord_max) { + //Revert + std::swap(arrow_color, text_color); + } + } + } + g->set_color(color); //Ensure color is still set correctly if we drew any arrows/text } -static void draw_rr_edges(int inode, ezgl::renderer* g) { - /* Draws all the edges that the user wants shown between inode and what it * - * connects to. inode is assumed to be a CHANX, CHANY, or IPIN. */ - t_draw_state* draw_state = get_draw_state_vars(); - auto& device_ctx = g_vpr_ctx.device(); - - t_rr_type from_type, to_type; - int to_node, from_ptc_num, to_ptc_num; - short switch_type; - - from_type = device_ctx.rr_nodes[inode].type(); - - if ((draw_state->draw_rr_toggle == DRAW_NODES_RR) - || (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_RR && (from_type == OPIN || from_type == SOURCE || from_type == IPIN)) - || (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_CBOX_RR && (from_type == SOURCE || from_type == IPIN))) { - return; /* Nothing to draw. */ - } - - from_ptc_num = device_ctx.rr_nodes[inode].ptc_num(); - - for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[inode].num_edges(); iedge < l; iedge++) { - to_node = device_ctx.rr_nodes[inode].edge_sink_node(iedge); - to_type = device_ctx.rr_nodes[to_node].type(); - to_ptc_num = device_ctx.rr_nodes[to_node].ptc_num(); - bool edge_configurable = device_ctx.rr_nodes[inode].edge_is_configurable(iedge); - - switch (from_type) { - case OPIN: - switch (to_type) { - case CHANX: - case CHANY: - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - // If OPIN was clicked on, set color to fan-out - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - // If CHANX or CHANY got clicked, set color to fan-in - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else { - g->set_color(ezgl::PINK); - } - draw_pin_to_chan_edge(inode, to_node, g); - break; - case IPIN: - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else { - g->set_color(ezgl::MEDIUM_PURPLE); - } - draw_pin_to_pin(inode, to_node, g); - break; - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", - inode, from_type, to_node, to_type); - break; - } - break; - - case CHANX: /* from_type */ - switch (to_type) { - case IPIN: - if (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_RR) { - break; - } - - if (draw_state->draw_rr_node[to_node].node_highlighted && draw_state->draw_rr_node[inode].color == DEFAULT_RR_NODE_COLOR) { - // If the IPIN is clicked on, draw connection to all the CHANX - // wire segments fanning into the pin. If a CHANX wire is clicked - // on, draw only the connection between that wire and the IPIN, with - // the pin fanning out from the wire. - break; - } - - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else { - g->set_color(blk_LIGHTSKYBLUE); - } - draw_pin_to_chan_edge(to_node, inode, g); - break; - - case CHANX: - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else if (!edge_configurable) { - ezgl::color color = blk_DARKGREY; - g->set_color(color); - } else { - g->set_color(blk_DARKGREEN); - } - switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); - draw_chanx_to_chanx_edge(inode, to_node, - to_ptc_num, switch_type, g); - break; - - case CHANY: - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else if (!edge_configurable) { - g->set_color(blk_DARKGREY); - } else { - g->set_color(blk_DARKGREEN); - } - switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); - draw_chanx_to_chany_edge(inode, from_ptc_num, to_node, - to_ptc_num, FROM_X_TO_Y, switch_type, g); - break; - - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", - inode, from_type, to_node, to_type); - break; - } - break; - - case CHANY: /* from_type */ - switch (to_type) { - case IPIN: - if (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_RR) { - break; - } - - if (draw_state->draw_rr_node[to_node].node_highlighted && draw_state->draw_rr_node[inode].color == DEFAULT_RR_NODE_COLOR) { - // If the IPIN is clicked on, draw connection to all the CHANY - // wire segments fanning into the pin. If a CHANY wire is clicked - // on, draw only the connection between that wire and the IPIN, with - // the pin fanning out from the wire. - break; - } - - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else { - g->set_color(blk_LIGHTSKYBLUE); - } - draw_pin_to_chan_edge(to_node, inode, g); - break; - - case CHANX: - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else if (!edge_configurable) { - ezgl::color color = blk_DARKGREY; - g->set_color(color); - } else { - g->set_color(blk_DARKGREEN); - } - switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); - draw_chanx_to_chany_edge(to_node, to_ptc_num, inode, - from_ptc_num, FROM_Y_TO_X, switch_type, g); - break; - - case CHANY: - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[to_node].color; - g->set_color(color); - } else if (draw_state->draw_rr_node[to_node].color == ezgl::MAGENTA) { - ezgl::color color = draw_state->draw_rr_node[inode].color; - g->set_color(color); - } else if (!edge_configurable) { - ezgl::color color = blk_DARKGREY; - g->set_color(color); - } else { - g->set_color(blk_DARKGREEN); - } - switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); - draw_chany_to_chany_edge(inode, to_node, - to_ptc_num, switch_type, g); - break; - - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", - inode, from_type, to_node, to_type); - break; - } - break; - case IPIN: // from_type - switch (to_type) { - case SINK: - g->set_color(ezgl::DARK_SLATE_BLUE); - draw_pin_to_sink(inode, to_node, g); - break; - - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", - inode, from_type, to_node, to_type); - break; - } - break; - case SOURCE: // from_type - switch (to_type) { - case OPIN: - g->set_color(ezgl::PLUM); - draw_source_to_pin(inode, to_node, g); - break; - - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", - inode, from_type, to_node, to_type); - break; - } - break; - default: /* from_type */ - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "draw_rr_edges called with node %d of type %d.\n", - inode, from_type); - break; - } - } /* End of for each edge loop */ +static void draw_rr_edges(int inode, ezgl::renderer *g) { + /* Draws all the edges that the user wants shown between inode and what it * + * connects to. inode is assumed to be a CHANX, CHANY, or IPIN. */ + t_draw_state *draw_state = get_draw_state_vars(); + auto &device_ctx = g_vpr_ctx.device(); + + t_rr_type from_type, to_type; + int to_node, from_ptc_num, to_ptc_num; + short switch_type; + + from_type = device_ctx.rr_nodes[inode].type(); + + if ((draw_state->draw_rr_toggle == DRAW_NODES_RR) + || (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_RR + && (from_type == OPIN || from_type == SOURCE + || from_type == IPIN)) + || (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_CBOX_RR + && (from_type == SOURCE || from_type == IPIN))) { + return; /* Nothing to draw. */ + } + + from_ptc_num = device_ctx.rr_nodes[inode].ptc_num(); + + for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[inode].num_edges(); + iedge < l; iedge++) { + to_node = device_ctx.rr_nodes[inode].edge_sink_node(iedge); + to_type = device_ctx.rr_nodes[to_node].type(); + to_ptc_num = device_ctx.rr_nodes[to_node].ptc_num(); + bool edge_configurable = + device_ctx.rr_nodes[inode].edge_is_configurable(iedge); + + switch (from_type) { + case OPIN: + switch (to_type) { + case CHANX: + case CHANY: + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + // If OPIN was clicked on, set color to fan-out + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + // If CHANX or CHANY got clicked, set color to fan-in + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else { + g->set_color(ezgl::PINK); + } + draw_pin_to_chan_edge(inode, to_node, g); + break; + case IPIN: + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else { + g->set_color(ezgl::MEDIUM_PURPLE); + } + draw_pin_to_pin(inode, to_node, g); + break; + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", + inode, from_type, to_node, to_type); + break; + } + break; + + case CHANX: /* from_type */ + switch (to_type) { + case IPIN: + if (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_RR) { + break; + } + + if (draw_state->draw_rr_node[to_node].node_highlighted + && draw_state->draw_rr_node[inode].color + == DEFAULT_RR_NODE_COLOR) { + // If the IPIN is clicked on, draw connection to all the CHANX + // wire segments fanning into the pin. If a CHANX wire is clicked + // on, draw only the connection between that wire and the IPIN, with + // the pin fanning out from the wire. + break; + } + + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else { + g->set_color(blk_LIGHTSKYBLUE); + } + draw_pin_to_chan_edge(to_node, inode, g); + break; + + case CHANX: + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else if (!edge_configurable) { + ezgl::color color = blk_DARKGREY; + g->set_color(color); + } else { + g->set_color(blk_DARKGREEN); + } + switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); + draw_chanx_to_chanx_edge(inode, to_node, to_ptc_num, + switch_type, g); + break; + + case CHANY: + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else if (!edge_configurable) { + g->set_color(blk_DARKGREY); + } else { + g->set_color(blk_DARKGREEN); + } + switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); + draw_chanx_to_chany_edge(inode, from_ptc_num, to_node, + to_ptc_num, FROM_X_TO_Y, switch_type, g); + break; + + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", + inode, from_type, to_node, to_type); + break; + } + break; + + case CHANY: /* from_type */ + switch (to_type) { + case IPIN: + if (draw_state->draw_rr_toggle == DRAW_NODES_SBOX_RR) { + break; + } + + if (draw_state->draw_rr_node[to_node].node_highlighted + && draw_state->draw_rr_node[inode].color + == DEFAULT_RR_NODE_COLOR) { + // If the IPIN is clicked on, draw connection to all the CHANY + // wire segments fanning into the pin. If a CHANY wire is clicked + // on, draw only the connection between that wire and the IPIN, with + // the pin fanning out from the wire. + break; + } + + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else { + g->set_color(blk_LIGHTSKYBLUE); + } + draw_pin_to_chan_edge(to_node, inode, g); + break; + + case CHANX: + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else if (!edge_configurable) { + ezgl::color color = blk_DARKGREY; + g->set_color(color); + } else { + g->set_color(blk_DARKGREEN); + } + switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); + draw_chanx_to_chany_edge(to_node, to_ptc_num, inode, + from_ptc_num, FROM_Y_TO_X, switch_type, g); + break; + + case CHANY: + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[to_node].color; + g->set_color(color); + } else if (draw_state->draw_rr_node[to_node].color + == ezgl::MAGENTA) { + ezgl::color color = draw_state->draw_rr_node[inode].color; + g->set_color(color); + } else if (!edge_configurable) { + ezgl::color color = blk_DARKGREY; + g->set_color(color); + } else { + g->set_color(blk_DARKGREEN); + } + switch_type = device_ctx.rr_nodes[inode].edge_switch(iedge); + draw_chany_to_chany_edge(inode, to_node, to_ptc_num, + switch_type, g); + break; + + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", + inode, from_type, to_node, to_type); + break; + } + break; + case IPIN: // from_type + switch (to_type) { + case SINK: + g->set_color(ezgl::DARK_SLATE_BLUE); + draw_pin_to_sink(inode, to_node, g); + break; + + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", + inode, from_type, to_node, to_type); + break; + } + break; + case SOURCE: // from_type + switch (to_type) { + case OPIN: + g->set_color(ezgl::PLUM); + draw_source_to_pin(inode, to_node, g); + break; + + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_rr_edges: node %d (type: %d) connects to node %d (type: %d).\n", + inode, from_type, to_node, to_type); + break; + } + break; + default: /* from_type */ + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "draw_rr_edges called with node %d of type %d.\n", inode, + from_type); + break; + } + } /* End of for each edge loop */ } -static void draw_x(float x, float y, float size, ezgl::renderer* g) { - /* Draws an X centered at (x,y). The width and height of the X are each * - * 2 * size. */ - g->draw_line({x - size, y + size}, {x + size, y - size}); - g->draw_line({x - size, y - size}, {x + size, y + size}); +static void draw_x(float x, float y, float size, ezgl::renderer *g) { + /* Draws an X centered at (x,y). The width and height of the X are each * + * 2 * size. */ + g->draw_line( { x - size, y + size }, { x + size, y - size }); + g->draw_line( { x - size, y - size }, { x + size, y + size }); } -static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, int chany_node, int chany_track, enum e_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(); - - /* Draws an edge (SBOX connection) between an x-directed channel and a * - * y-directed channel. */ - - float x1, y1, x2, y2; - ezgl::rectangle chanx_bbox; - ezgl::rectangle chany_bbox; - int chanx_xlow, chany_x, chany_ylow, chanx_y; - - /* Get the coordinates of the CHANX and CHANY segments. */ - chanx_bbox = draw_get_rr_chan_bbox(chanx_node); - chany_bbox = draw_get_rr_chan_bbox(chany_node); - - /* (x1,y1): point on CHANX segment, (x2,y2): point on CHANY segment. */ - - y1 = chanx_bbox.bottom(); - x2 = chany_bbox.left(); - - chanx_xlow = device_ctx.rr_nodes[chanx_node].xlow(); - chanx_y = device_ctx.rr_nodes[chanx_node].ylow(); - chany_x = device_ctx.rr_nodes[chany_node].xlow(); - chany_ylow = device_ctx.rr_nodes[chany_node].ylow(); - - if (chanx_xlow <= chany_x) { /* Can draw connection going right */ - /* Connection not at end of the CHANX segment. */ - x1 = draw_coords->tile_x[chany_x] + draw_coords->get_tile_width(); - - if (device_ctx.rr_nodes[chanx_node].direction() != BI_DIRECTION) { - if (edge_dir == FROM_X_TO_Y) { - if ((chanx_track % 2) == 1) { /* If dec wire, then going left */ - x1 = draw_coords->tile_x[chany_x + 1]; - } - } - } - - } else { /* Must draw connection going left. */ - x1 = chanx_bbox.left(); - } - - if (chany_ylow <= chanx_y) { /* Can draw connection going up. */ - /* Connection not at end of the CHANY segment. */ - y2 = draw_coords->tile_y[chanx_y] + draw_coords->get_tile_width(); - - if (device_ctx.rr_nodes[chany_node].direction() != BI_DIRECTION) { - if (edge_dir == FROM_Y_TO_X) { - if ((chany_track % 2) == 1) { /* If dec wire, then going down */ - y2 = draw_coords->tile_y[chanx_y + 1]; - } - } - } - - } else { /* Must draw connection going down. */ - y2 = chany_bbox.bottom(); - } - - g->draw_line({x1, y1}, {x2, y2}); - - if (draw_state->draw_rr_toggle == DRAW_ALL_RR || draw_state->draw_rr_node[chanx_node].node_highlighted) { - if (edge_dir == FROM_X_TO_Y) { - draw_rr_switch(x1, y1, x2, y2, device_ctx.rr_switch_inf[switch_type].buffered(), device_ctx.rr_switch_inf[switch_type].configurable(), g); - } else { - draw_rr_switch(x2, y2, x1, y1, device_ctx.rr_switch_inf[switch_type].buffered(), device_ctx.rr_switch_inf[switch_type].configurable(), g); - } - } +static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, + int chany_node, int chany_track, enum e_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(); + + /* Draws an edge (SBOX connection) between an x-directed channel and a * + * y-directed channel. */ + + float x1, y1, x2, y2; + ezgl::rectangle chanx_bbox; + ezgl::rectangle chany_bbox; + int chanx_xlow, chany_x, chany_ylow, chanx_y; + + /* Get the coordinates of the CHANX and CHANY segments. */ + chanx_bbox = draw_get_rr_chan_bbox(chanx_node); + chany_bbox = draw_get_rr_chan_bbox(chany_node); + + /* (x1,y1): point on CHANX segment, (x2,y2): point on CHANY segment. */ + + y1 = chanx_bbox.bottom(); + x2 = chany_bbox.left(); + + chanx_xlow = device_ctx.rr_nodes[chanx_node].xlow(); + chanx_y = device_ctx.rr_nodes[chanx_node].ylow(); + chany_x = device_ctx.rr_nodes[chany_node].xlow(); + chany_ylow = device_ctx.rr_nodes[chany_node].ylow(); + + if (chanx_xlow <= chany_x) { /* Can draw connection going right */ + /* Connection not at end of the CHANX segment. */ + x1 = draw_coords->tile_x[chany_x] + draw_coords->get_tile_width(); + + if (device_ctx.rr_nodes[chanx_node].direction() != BI_DIRECTION) { + if (edge_dir == FROM_X_TO_Y) { + if ((chanx_track % 2) == 1) { /* If dec wire, then going left */ + x1 = draw_coords->tile_x[chany_x + 1]; + } + } + } + + } else { /* Must draw connection going left. */ + x1 = chanx_bbox.left(); + } + + if (chany_ylow <= chanx_y) { /* Can draw connection going up. */ + /* Connection not at end of the CHANY segment. */ + y2 = draw_coords->tile_y[chanx_y] + draw_coords->get_tile_width(); + + if (device_ctx.rr_nodes[chany_node].direction() != BI_DIRECTION) { + if (edge_dir == FROM_Y_TO_X) { + if ((chany_track % 2) == 1) { /* If dec wire, then going down */ + y2 = draw_coords->tile_y[chanx_y + 1]; + } + } + } + + } else { /* Must draw connection going down. */ + y2 = chany_bbox.bottom(); + } + + g->draw_line( { x1, y1 }, { x2, y2 }); + + if (draw_state->draw_rr_toggle == DRAW_ALL_RR + || draw_state->draw_rr_node[chanx_node].node_highlighted) { + if (edge_dir == FROM_X_TO_Y) { + draw_rr_switch(x1, y1, x2, y2, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } else { + draw_rr_switch(x2, y2, x1, y1, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } + } } -static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, short switch_type, ezgl::renderer* g) { - /* Draws a connection between two x-channel segments. Passing in the track * - * numbers allows this routine to be used for both rr_graph and routing * - * drawing-> */ - - 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(); - - float x1, x2, y1, y2; - ezgl::rectangle from_chan; - ezgl::rectangle to_chan; - int from_xlow, to_xlow, from_xhigh, to_xhigh; - - // Get the coordinates of the channel wires. - from_chan = draw_get_rr_chan_bbox(from_node); - to_chan = draw_get_rr_chan_bbox(to_node); - - /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ - - y1 = from_chan.bottom(); - y2 = to_chan.bottom(); - - from_xlow = device_ctx.rr_nodes[from_node].xlow(); - from_xhigh = device_ctx.rr_nodes[from_node].xhigh(); - to_xlow = device_ctx.rr_nodes[to_node].xlow(); - to_xhigh = device_ctx.rr_nodes[to_node].xhigh(); - if (to_xhigh < from_xlow) { /* From right to left */ - /* UDSD Note by WMF: could never happen for INC wires, unless U-turn. For DEC - * wires this handles well */ - x1 = from_chan.left(); - x2 = to_chan.right(); - } else if (to_xlow > from_xhigh) { /* From left to right */ - /* UDSD Note by WMF: could never happen for DEC wires, unless U-turn. For INC - * wires this handles well */ - x1 = from_chan.right(); - x2 = to_chan.left(); - } - - /* Segments overlap in the channel. Figure out best way to draw. Have to * - * make sure the drawing is symmetric in the from rr and to rr so the edges * - * will be drawn on top of each other for bidirectional connections. */ - - else { - if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { - /* must connect to to_node's wire beginning at x2 */ - if (to_track % 2 == 0) { /* INC wire starts at leftmost edge */ - VTR_ASSERT(from_xlow < to_xlow); - x2 = to_chan.left(); - /* since no U-turns from_track must be INC as well */ - x1 = draw_coords->tile_x[to_xlow - 1] + draw_coords->get_tile_width(); - } else { /* DEC wire starts at rightmost edge */ - VTR_ASSERT(from_xhigh > to_xhigh); - x2 = to_chan.right(); - x1 = draw_coords->tile_x[to_xhigh + 1]; - } - } else { - if (to_xlow < from_xlow) { /* Draw from left edge of one to other */ - x1 = from_chan.left(); - x2 = draw_coords->tile_x[from_xlow - 1] + draw_coords->get_tile_width(); - } else if (from_xlow < to_xlow) { - x1 = draw_coords->tile_x[to_xlow - 1] + draw_coords->get_tile_width(); - x2 = to_chan.left(); - - } /* The following then is executed when from_xlow == to_xlow */ - else if (to_xhigh > from_xhigh) { /* Draw from right edge of one to other */ - x1 = from_chan.right(); - x2 = draw_coords->tile_x[from_xhigh + 1]; - } else if (from_xhigh > to_xhigh) { - x1 = draw_coords->tile_x[to_xhigh + 1]; - x2 = to_chan.right(); - } else { /* Complete overlap: start and end both align. Draw outside the sbox */ - x1 = from_chan.left(); - x2 = from_chan.left() + draw_coords->get_tile_width(); - } - } - } - - g->draw_line({x1, y1}, {x2, y2}); - - if (draw_state->draw_rr_toggle == DRAW_ALL_RR || draw_state->draw_rr_node[from_node].node_highlighted) { - draw_rr_switch(x1, y1, x2, y2, device_ctx.rr_switch_inf[switch_type].buffered(), device_ctx.rr_switch_inf[switch_type].configurable(), g); - } +static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, + short switch_type, ezgl::renderer *g) { + /* Draws a connection between two x-channel segments. Passing in the track * + * numbers allows this routine to be used for both rr_graph and routing * + * drawing-> */ + + 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(); + + float x1, x2, y1, y2; + ezgl::rectangle from_chan; + ezgl::rectangle to_chan; + int from_xlow, to_xlow, from_xhigh, to_xhigh; + + // Get the coordinates of the channel wires. + from_chan = draw_get_rr_chan_bbox(from_node); + to_chan = draw_get_rr_chan_bbox(to_node); + + /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ + + y1 = from_chan.bottom(); + y2 = to_chan.bottom(); + + from_xlow = device_ctx.rr_nodes[from_node].xlow(); + from_xhigh = device_ctx.rr_nodes[from_node].xhigh(); + to_xlow = device_ctx.rr_nodes[to_node].xlow(); + to_xhigh = device_ctx.rr_nodes[to_node].xhigh(); + if (to_xhigh < from_xlow) { /* From right to left */ + /* UDSD Note by WMF: could never happen for INC wires, unless U-turn. For DEC + * wires this handles well */ + x1 = from_chan.left(); + x2 = to_chan.right(); + } else if (to_xlow > from_xhigh) { /* From left to right */ + /* UDSD Note by WMF: could never happen for DEC wires, unless U-turn. For INC + * wires this handles well */ + x1 = from_chan.right(); + x2 = to_chan.left(); + } + + /* Segments overlap in the channel. Figure out best way to draw. Have to * + * make sure the drawing is symmetric in the from rr and to rr so the edges * + * will be drawn on top of each other for bidirectional connections. */ + + else { + if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { + /* must connect to to_node's wire beginning at x2 */ + if (to_track % 2 == 0) { /* INC wire starts at leftmost edge */ + VTR_ASSERT(from_xlow < to_xlow); + x2 = to_chan.left(); + /* since no U-turns from_track must be INC as well */ + x1 = draw_coords->tile_x[to_xlow - 1] + + draw_coords->get_tile_width(); + } else { /* DEC wire starts at rightmost edge */ + VTR_ASSERT(from_xhigh > to_xhigh); + x2 = to_chan.right(); + x1 = draw_coords->tile_x[to_xhigh + 1]; + } + } else { + if (to_xlow < from_xlow) { /* Draw from left edge of one to other */ + x1 = from_chan.left(); + x2 = draw_coords->tile_x[from_xlow - 1] + + draw_coords->get_tile_width(); + } else if (from_xlow < to_xlow) { + x1 = draw_coords->tile_x[to_xlow - 1] + + draw_coords->get_tile_width(); + x2 = to_chan.left(); + + } /* The following then is executed when from_xlow == to_xlow */ + else if (to_xhigh > from_xhigh) { /* Draw from right edge of one to other */ + x1 = from_chan.right(); + x2 = draw_coords->tile_x[from_xhigh + 1]; + } else if (from_xhigh > to_xhigh) { + x1 = draw_coords->tile_x[to_xhigh + 1]; + x2 = to_chan.right(); + } else { /* Complete overlap: start and end both align. Draw outside the sbox */ + x1 = from_chan.left(); + x2 = from_chan.left() + draw_coords->get_tile_width(); + } + } + } + + g->draw_line( { x1, y1 }, { x2, y2 }); + + if (draw_state->draw_rr_toggle == DRAW_ALL_RR + || draw_state->draw_rr_node[from_node].node_highlighted) { + draw_rr_switch(x1, y1, x2, y2, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } } -static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, 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(); - - /* Draws a connection between two y-channel segments. Passing in the track * - * numbers allows this routine to be used for both rr_graph and routing * - * drawing-> */ - - float x1, x2, y1, y2; - ezgl::rectangle from_chan; - ezgl::rectangle to_chan; - int from_ylow, to_ylow, from_yhigh, to_yhigh; //, from_x, to_x; - - // Get the coordinates of the channel wires. - from_chan = draw_get_rr_chan_bbox(from_node); - to_chan = draw_get_rr_chan_bbox(to_node); - - // from_x = device_ctx.rr_nodes[from_node].xlow(); - // to_x = device_ctx.rr_nodes[to_node].xlow(); - from_ylow = device_ctx.rr_nodes[from_node].ylow(); - from_yhigh = device_ctx.rr_nodes[from_node].yhigh(); - to_ylow = device_ctx.rr_nodes[to_node].ylow(); - to_yhigh = device_ctx.rr_nodes[to_node].yhigh(); - - /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ - - x1 = from_chan.left(); - x2 = to_chan.left(); - - if (to_yhigh < from_ylow) { /* From upper to lower */ - y1 = from_chan.bottom(); - y2 = to_chan.top(); - } else if (to_ylow > from_yhigh) { /* From lower to upper */ - y1 = from_chan.top(); - y2 = to_chan.bottom(); - } - - /* Segments overlap in the channel. Figure out best way to draw. Have to * - * make sure the drawing is symmetric in the from rr and to rr so the edges * - * will be drawn on top of each other for bidirectional connections. */ - - /* UDSD Modification by WMF Begin */ - else { - if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { - if (to_track % 2 == 0) { /* INC wire starts at bottom edge */ - - y2 = to_chan.bottom(); - /* since no U-turns from_track must be INC as well */ - y1 = draw_coords->tile_y[to_ylow - 1] + draw_coords->get_tile_width(); - } else { /* DEC wire starts at top edge */ - - y2 = to_chan.top(); - y1 = draw_coords->tile_y[to_yhigh + 1]; - } - } else { - if (to_ylow < from_ylow) { /* Draw from bottom edge of one to other. */ - y1 = from_chan.bottom(); - y2 = draw_coords->tile_y[from_ylow - 1] + draw_coords->get_tile_width(); - } else if (from_ylow < to_ylow) { - y1 = draw_coords->tile_y[to_ylow - 1] + draw_coords->get_tile_width(); - y2 = to_chan.bottom(); - } else if (to_yhigh > from_yhigh) { /* Draw from top edge of one to other. */ - y1 = from_chan.top(); - y2 = draw_coords->tile_y[from_yhigh + 1]; - } else if (from_yhigh > to_yhigh) { - y1 = draw_coords->tile_y[to_yhigh + 1]; - y2 = to_chan.top(); - } else { /* Complete overlap: start and end both align. Draw outside the sbox */ - y1 = from_chan.bottom(); - y2 = from_chan.bottom() + draw_coords->get_tile_width(); - } - } - } - - /* UDSD Modification by WMF End */ - g->draw_line({x1, y1}, {x2, y2}); - - if (draw_state->draw_rr_toggle == DRAW_ALL_RR || draw_state->draw_rr_node[from_node].node_highlighted) { - draw_rr_switch(x1, y1, x2, y2, device_ctx.rr_switch_inf[switch_type].buffered(), device_ctx.rr_switch_inf[switch_type].configurable(), g); - } +static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, + 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(); + + /* Draws a connection between two y-channel segments. Passing in the track * + * numbers allows this routine to be used for both rr_graph and routing * + * drawing-> */ + + float x1, x2, y1, y2; + ezgl::rectangle from_chan; + ezgl::rectangle to_chan; + int from_ylow, to_ylow, from_yhigh, to_yhigh; //, from_x, to_x; + + // Get the coordinates of the channel wires. + from_chan = draw_get_rr_chan_bbox(from_node); + to_chan = draw_get_rr_chan_bbox(to_node); + + // from_x = device_ctx.rr_nodes[from_node].xlow(); + // to_x = device_ctx.rr_nodes[to_node].xlow(); + from_ylow = device_ctx.rr_nodes[from_node].ylow(); + from_yhigh = device_ctx.rr_nodes[from_node].yhigh(); + to_ylow = device_ctx.rr_nodes[to_node].ylow(); + to_yhigh = device_ctx.rr_nodes[to_node].yhigh(); + + /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ + + x1 = from_chan.left(); + x2 = to_chan.left(); + + if (to_yhigh < from_ylow) { /* From upper to lower */ + y1 = from_chan.bottom(); + y2 = to_chan.top(); + } else if (to_ylow > from_yhigh) { /* From lower to upper */ + y1 = from_chan.top(); + y2 = to_chan.bottom(); + } + + /* Segments overlap in the channel. Figure out best way to draw. Have to * + * make sure the drawing is symmetric in the from rr and to rr so the edges * + * will be drawn on top of each other for bidirectional connections. */ + + /* UDSD Modification by WMF Begin */ + else { + if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { + if (to_track % 2 == 0) { /* INC wire starts at bottom edge */ + + y2 = to_chan.bottom(); + /* since no U-turns from_track must be INC as well */ + y1 = draw_coords->tile_y[to_ylow - 1] + + draw_coords->get_tile_width(); + } else { /* DEC wire starts at top edge */ + + y2 = to_chan.top(); + y1 = draw_coords->tile_y[to_yhigh + 1]; + } + } else { + if (to_ylow < from_ylow) { /* Draw from bottom edge of one to other. */ + y1 = from_chan.bottom(); + y2 = draw_coords->tile_y[from_ylow - 1] + + draw_coords->get_tile_width(); + } else if (from_ylow < to_ylow) { + y1 = draw_coords->tile_y[to_ylow - 1] + + draw_coords->get_tile_width(); + y2 = to_chan.bottom(); + } else if (to_yhigh > from_yhigh) { /* Draw from top edge of one to other. */ + y1 = from_chan.top(); + y2 = draw_coords->tile_y[from_yhigh + 1]; + } else if (from_yhigh > to_yhigh) { + y1 = draw_coords->tile_y[to_yhigh + 1]; + y2 = to_chan.top(); + } else { /* Complete overlap: start and end both align. Draw outside the sbox */ + y1 = from_chan.bottom(); + y2 = from_chan.bottom() + draw_coords->get_tile_width(); + } + } + } + + /* UDSD Modification by WMF End */ + g->draw_line( { x1, y1 }, { x2, y2 }); + + if (draw_state->draw_rr_toggle == DRAW_ALL_RR + || draw_state->draw_rr_node[from_node].node_highlighted) { + draw_rr_switch(x1, y1, x2, y2, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } } /* This function computes and returns the boundary coordinates of a channel @@ -2044,445 +2245,466 @@ static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, s * TODO: Fix this for global routing, currently for detailed only. */ ezgl::rectangle draw_get_rr_chan_bbox(int inode) { - double left = 0, right = 0, top = 0, bottom = 0; - t_draw_coords* draw_coords = get_draw_coords_vars(); - auto& device_ctx = g_vpr_ctx.device(); - - switch (device_ctx.rr_nodes[inode].type()) { - case CHANX: - left = draw_coords->tile_x[device_ctx.rr_nodes[inode].xlow()]; - right = draw_coords->tile_x[device_ctx.rr_nodes[inode].xhigh()] - + draw_coords->get_tile_width(); - bottom = draw_coords->tile_y[device_ctx.rr_nodes[inode].ylow()] - + draw_coords->get_tile_width() - + (1. + device_ctx.rr_nodes[inode].ptc_num()); - top = draw_coords->tile_y[device_ctx.rr_nodes[inode].ylow()] - + draw_coords->get_tile_width() - + (1. + device_ctx.rr_nodes[inode].ptc_num()); - break; - case CHANY: - left = draw_coords->tile_x[device_ctx.rr_nodes[inode].xlow()] - + draw_coords->get_tile_width() - + (1. + device_ctx.rr_nodes[inode].ptc_num()); - right = draw_coords->tile_x[device_ctx.rr_nodes[inode].xlow()] - + draw_coords->get_tile_width() - + (1. + device_ctx.rr_nodes[inode].ptc_num()); - bottom = draw_coords->tile_y[device_ctx.rr_nodes[inode].ylow()]; - top = draw_coords->tile_y[device_ctx.rr_nodes[inode].yhigh()] - + draw_coords->get_tile_width(); - break; - default: - // a problem. leave at default value (ie. zeros) - break; - } - ezgl::rectangle bound_box({left, bottom}, {right, top}); - - return bound_box; + double left = 0, right = 0, top = 0, bottom = 0; + t_draw_coords *draw_coords = get_draw_coords_vars(); + auto &device_ctx = g_vpr_ctx.device(); + + switch (device_ctx.rr_nodes[inode].type()) { + case CHANX: + left = draw_coords->tile_x[device_ctx.rr_nodes[inode].xlow()]; + right = draw_coords->tile_x[device_ctx.rr_nodes[inode].xhigh()] + + draw_coords->get_tile_width(); + bottom = draw_coords->tile_y[device_ctx.rr_nodes[inode].ylow()] + + draw_coords->get_tile_width() + + (1. + device_ctx.rr_nodes[inode].ptc_num()); + top = draw_coords->tile_y[device_ctx.rr_nodes[inode].ylow()] + + draw_coords->get_tile_width() + + (1. + device_ctx.rr_nodes[inode].ptc_num()); + break; + case CHANY: + left = draw_coords->tile_x[device_ctx.rr_nodes[inode].xlow()] + + draw_coords->get_tile_width() + + (1. + device_ctx.rr_nodes[inode].ptc_num()); + right = draw_coords->tile_x[device_ctx.rr_nodes[inode].xlow()] + + draw_coords->get_tile_width() + + (1. + device_ctx.rr_nodes[inode].ptc_num()); + bottom = draw_coords->tile_y[device_ctx.rr_nodes[inode].ylow()]; + top = draw_coords->tile_y[device_ctx.rr_nodes[inode].yhigh()] + + draw_coords->get_tile_width(); + break; + default: + // a problem. leave at default value (ie. zeros) + break; + } + ezgl::rectangle bound_box( { left, bottom }, { right, top }); + + return bound_box; } -static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, bool buffered, bool configurable, ezgl::renderer* g) { - /* 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. */ - - if (!buffered) { - if (configurable) { /* Draw a circle for a pass transistor */ - float xcen = from_x + (to_x - from_x) / 10.; - float ycen = from_y + (to_y - from_y) / 10.; - const float switch_rad = 0.15; - g->draw_arc({xcen, ycen}, switch_rad, 0., 360.); - } else { - //Pass, nothing to draw - } - } else { /* Buffer */ - if (from_x == to_x || from_y == to_y) { - //Straight connection - draw_triangle_along_line(g, {from_x, from_y}, {to_x, to_y}, SB_EDGE_STRAIGHT_ARROW_POSITION); - } else { - //Turn connection - draw_triangle_along_line(g, {from_x, from_y}, {to_x, to_y}, SB_EDGE_TURN_ARROW_POSITION); - } - } +static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, + bool buffered, bool configurable, ezgl::renderer *g) { + /* 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. */ + + if (!buffered) { + if (configurable) { /* Draw a circle for a pass transistor */ + float xcen = from_x + (to_x - from_x) / 10.; + float ycen = from_y + (to_y - from_y) / 10.; + const float switch_rad = 0.15; + g->draw_arc( { xcen, ycen }, switch_rad, 0., 360.); + } else { + //Pass, nothing to draw + } + } else { /* Buffer */ + if (from_x == to_x || from_y == to_y) { + //Straight connection + draw_triangle_along_line(g, { from_x, from_y }, { to_x, to_y }, + SB_EDGE_STRAIGHT_ARROW_POSITION); + } else { + //Turn connection + draw_triangle_along_line(g, { from_x, from_y }, { to_x, to_y }, + SB_EDGE_TURN_ARROW_POSITION); + } + } } -static void draw_rr_pin(int 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. */ - - t_draw_coords* draw_coords = get_draw_coords_vars(); - - float xcen, ycen; - char str[vtr::bufsize]; - auto& device_ctx = g_vpr_ctx.device(); - - int ipin = device_ctx.rr_nodes[inode].ptc_num(); - - g->set_color(color); - - /* TODO: This is where we can hide fringe physical pins and also identify globals (hide, color, show) */ - /* As nodes may appear on more than one side, walk through the possible nodes - * - draw the pin on each side that it appears - */ - for (const e_side& pin_side : SIDES) { - if (!device_ctx.rr_nodes[inode].is_node_on_specific_side(pin_side)) { - continue; - } - draw_get_rr_pin_coords(inode, &xcen, &ycen, pin_side); - g->fill_rectangle({xcen - draw_coords->pin_size, ycen - draw_coords->pin_size}, - {xcen + draw_coords->pin_size, ycen + draw_coords->pin_size}); - sprintf(str, "%d", ipin); - g->set_color(ezgl::BLACK); - g->draw_text({xcen, ycen}, str, 2 * draw_coords->pin_size, 2 * draw_coords->pin_size); - g->set_color(color); - } +static void draw_rr_pin(int 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. */ + + t_draw_coords *draw_coords = get_draw_coords_vars(); + + float xcen, ycen; + char str[vtr::bufsize]; + auto &device_ctx = g_vpr_ctx.device(); + + int ipin = device_ctx.rr_nodes[inode].ptc_num(); + + g->set_color(color); + + /* TODO: This is where we can hide fringe physical pins and also identify globals (hide, color, show) */ + /* As nodes may appear on more than one side, walk through the possible nodes + * - draw the pin on each side that it appears + */ + for (const e_side &pin_side : SIDES) { + if (!device_ctx.rr_nodes[inode].is_node_on_specific_side(pin_side)) { + continue; + } + draw_get_rr_pin_coords(inode, &xcen, &ycen, pin_side); + g->fill_rectangle( + { xcen - draw_coords->pin_size, ycen - draw_coords->pin_size }, + { xcen + draw_coords->pin_size, ycen + draw_coords->pin_size }); + sprintf(str, "%d", ipin); + g->set_color(ezgl::BLACK); + g->draw_text( { xcen, ycen }, str, 2 * draw_coords->pin_size, + 2 * draw_coords->pin_size); + g->set_color(color); + } } /* Returns the coordinates at which the center of this pin should be drawn. * * inode gives the node number, and iside gives the side of the clb or pad * * the physical pin is on. */ -void draw_get_rr_pin_coords(int inode, float* xcen, float* ycen, const e_side& pin_side) { - auto& device_ctx = g_vpr_ctx.device(); - draw_get_rr_pin_coords(device_ctx.rr_nodes[inode], xcen, ycen, pin_side); +void draw_get_rr_pin_coords(int inode, float *xcen, float *ycen, + const e_side &pin_side) { + auto &device_ctx = g_vpr_ctx.device(); + draw_get_rr_pin_coords(device_ctx.rr_nodes[inode], xcen, ycen, pin_side); } -void draw_get_rr_pin_coords(const t_rr_node& node, float* xcen, float* ycen, const e_side& pin_side) { - t_draw_coords* draw_coords = get_draw_coords_vars(); - - int i, j, k, ipin, pins_per_sub_tile; - float offset, xc, yc, step; - t_physical_tile_type_ptr type; - auto& device_ctx = g_vpr_ctx.device(); - - i = node.xlow(); - j = node.ylow(); - - xc = draw_coords->tile_x[i]; - yc = draw_coords->tile_y[j]; - - ipin = node.ptc_num(); - type = device_ctx.grid[i][j].type; - pins_per_sub_tile = type->num_pins / type->capacity; - k = ipin / pins_per_sub_tile; - - /* Since pins numbers go across all sub_tiles in a block in order - * we can treat as a block box for this step */ - - /* For each sub_tile we need and extra padding space */ - step = (float)(draw_coords->get_tile_width()) / (float)(type->num_pins + type->capacity); - offset = (ipin + k + 1) * step; - - switch (pin_side) { - case LEFT: - yc += offset; - break; - - case RIGHT: - xc += draw_coords->get_tile_width(); - yc += offset; - break; - - case BOTTOM: - xc += offset; - break; - - case TOP: - xc += offset; - yc += draw_coords->get_tile_width(); - break; - - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_get_rr_pin_coords: Unexpected side %s.\n", - SIDE_STRING[pin_side]); - break; - } - - *xcen = xc; - *ycen = yc; +void draw_get_rr_pin_coords(const t_rr_node &node, float *xcen, float *ycen, + const e_side &pin_side) { + t_draw_coords *draw_coords = get_draw_coords_vars(); + + int i, j, k, ipin, pins_per_sub_tile; + float offset, xc, yc, step; + t_physical_tile_type_ptr type; + auto &device_ctx = g_vpr_ctx.device(); + + i = node.xlow(); + j = node.ylow(); + + xc = draw_coords->tile_x[i]; + yc = draw_coords->tile_y[j]; + + ipin = node.ptc_num(); + type = device_ctx.grid[i][j].type; + pins_per_sub_tile = type->num_pins / type->capacity; + k = ipin / pins_per_sub_tile; + + /* Since pins numbers go across all sub_tiles in a block in order + * we can treat as a block box for this step */ + + /* For each sub_tile we need and extra padding space */ + step = (float) (draw_coords->get_tile_width()) + / (float) (type->num_pins + type->capacity); + offset = (ipin + k + 1) * step; + + switch (pin_side) { + case LEFT: + yc += offset; + break; + + case RIGHT: + xc += draw_coords->get_tile_width(); + yc += offset; + break; + + case BOTTOM: + xc += offset; + break; + + case TOP: + xc += offset; + yc += draw_coords->get_tile_width(); + break; + + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_get_rr_pin_coords: Unexpected side %s.\n", + SIDE_STRING[pin_side]); + break; + } + + *xcen = xc; + *ycen = yc; } -static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer* g) { - t_draw_coords* draw_coords = get_draw_coords_vars(); +static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer *g) { + t_draw_coords *draw_coords = get_draw_coords_vars(); - auto& device_ctx = g_vpr_ctx.device(); + auto &device_ctx = g_vpr_ctx.device(); - float xcen, ycen; - draw_get_rr_src_sink_coords(device_ctx.rr_nodes[inode], &xcen, &ycen); + float xcen, ycen; + draw_get_rr_src_sink_coords(device_ctx.rr_nodes[inode], &xcen, &ycen); - g->set_color(color); + g->set_color(color); - g->fill_rectangle({xcen - draw_coords->pin_size, ycen - draw_coords->pin_size}, - {xcen + draw_coords->pin_size, ycen + draw_coords->pin_size}); + g->fill_rectangle( + { xcen - draw_coords->pin_size, ycen - draw_coords->pin_size }, + { xcen + draw_coords->pin_size, ycen + draw_coords->pin_size }); - std::string str = vtr::string_fmt("%d", device_ctx.rr_nodes[inode].ptc_num()); - g->set_color(ezgl::BLACK); - g->draw_text({xcen, ycen}, str.c_str(), 2 * draw_coords->pin_size, 2 * draw_coords->pin_size); - g->set_color(color); + std::string str = vtr::string_fmt("%d", + device_ctx.rr_nodes[inode].ptc_num()); + g->set_color(ezgl::BLACK); + g->draw_text( { xcen, ycen }, str.c_str(), 2 * draw_coords->pin_size, + 2 * draw_coords->pin_size); + g->set_color(color); } -static void draw_get_rr_src_sink_coords(const t_rr_node& node, float* xcen, float* ycen) { - t_draw_coords* draw_coords = get_draw_coords_vars(); +static void draw_get_rr_src_sink_coords(const t_rr_node &node, float *xcen, + float *ycen) { + t_draw_coords *draw_coords = get_draw_coords_vars(); - auto& device_ctx = g_vpr_ctx.device(); - t_physical_tile_type_ptr tile_type = device_ctx.grid[node.xlow()][node.ylow()].type; + auto &device_ctx = g_vpr_ctx.device(); + t_physical_tile_type_ptr tile_type = + device_ctx.grid[node.xlow()][node.ylow()].type; - //Number of classes (i.e. src/sinks) we need to draw - float num_class = tile_type->class_inf.size(); + //Number of classes (i.e. src/sinks) we need to draw + float num_class = tile_type->class_inf.size(); - int height = tile_type->height; //Height in blocks + int height = tile_type->height; //Height in blocks - //How many classes to draw per unit block height - int class_per_height = num_class; - if (height > 1) { - class_per_height = num_class / (height - 1); - } + //How many classes to draw per unit block height + int class_per_height = num_class; + if (height > 1) { + class_per_height = num_class / (height - 1); + } - int class_height_offset = node.class_num() / class_per_height; //Offset wrt block height - int class_height_shift = node.class_num() % class_per_height; //Offset within unit block + int class_height_offset = node.class_num() / class_per_height; //Offset wrt block height + int class_height_shift = node.class_num() % class_per_height; //Offset within unit block - float xc = draw_coords->tile_x[node.xlow()]; - float yc = draw_coords->tile_y[node.ylow() + class_height_offset]; + float xc = draw_coords->tile_x[node.xlow()]; + float yc = draw_coords->tile_y[node.ylow() + class_height_offset]; - *xcen = xc + 0.5 * draw_coords->get_tile_width(); + *xcen = xc + 0.5 * draw_coords->get_tile_width(); - float class_section_height = class_per_height + 1; + float class_section_height = class_per_height + 1; - float ypos = (class_height_shift + 1) / class_section_height; - *ycen = yc + ypos * draw_coords->get_tile_height(); + float ypos = (class_height_shift + 1) / class_section_height; + *ycen = yc + ypos * draw_coords->get_tile_height(); } /* Draws the nets in the positions fixed by the router. If draw_net_type is * * ALL_NETS, draw all the nets. If it is HIGHLIGHTED, draw only the nets * * that are not coloured black (useful for drawing over the rr_graph). */ -static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer* g) { - /* Next free track in each channel segment if routing is GLOBAL */ +static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer *g) { + /* Next free track in each channel segment if routing is GLOBAL */ - auto& cluster_ctx = g_vpr_ctx.clustering(); + auto &cluster_ctx = g_vpr_ctx.clustering(); - t_draw_state* draw_state = get_draw_state_vars(); + t_draw_state *draw_state = get_draw_state_vars(); - float NET_ALPHA = draw_state->net_alpha; + float NET_ALPHA = draw_state->net_alpha; - g->set_line_dash(ezgl::line_dash::none); - g->set_color(ezgl::BLACK, ezgl::BLACK.alpha * NET_ALPHA); + g->set_line_dash(ezgl::line_dash::none); + g->set_color(ezgl::BLACK, ezgl::BLACK.alpha * NET_ALPHA); - /* Now draw each net, one by one. */ + /* Now draw each net, one by one. */ - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - if (draw_net_type == HIGHLIGHTED && draw_state->net_color[net_id] == ezgl::BLACK) - continue; + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + if (draw_net_type == HIGHLIGHTED + && draw_state->net_color[net_id] == ezgl::BLACK) + continue; - draw_routed_net(net_id, g); - } /* End for (each net) */ + draw_routed_net(net_id, g); + } /* End for (each net) */ } -static void draw_routed_net(ClusterNetId net_id, ezgl::renderer* g) { - auto& route_ctx = g_vpr_ctx.routing(); - auto& cluster_ctx = g_vpr_ctx.clustering(); +static void draw_routed_net(ClusterNetId 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(); + t_draw_state *draw_state = get_draw_state_vars(); - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) /* Don't draw. */ - return; + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) /* Don't draw. */ + return; - if (route_ctx.trace[net_id].head == nullptr) /* No routing-> Skip. (Allows me to draw */ - return; /* partially complete routes). */ + if (route_ctx.trace[net_id].head == nullptr) /* No routing-> Skip. (Allows me to draw */ + return; /* partially complete routes). */ - t_trace* tptr = route_ctx.trace[net_id].head; /* SOURCE to start */ - int inode = tptr->index; + t_trace *tptr = route_ctx.trace[net_id].head; /* SOURCE to start */ + int inode = tptr->index; - std::vector rr_nodes_to_draw; - rr_nodes_to_draw.push_back(inode); - for (;;) { - tptr = tptr->next; - inode = tptr->index; + std::vector rr_nodes_to_draw; + rr_nodes_to_draw.push_back(inode); + for (;;) { + tptr = tptr->next; + inode = tptr->index; - 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[net_id]; - draw_state->draw_rr_node[inode].node_highlighted = true; - } else { - /* If not highlighted, draw the node in default color. */ - draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; - } + 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[net_id]; + draw_state->draw_rr_node[inode].node_highlighted = true; + } else { + /* If not highlighted, draw the node in default color. */ + draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; + } - rr_nodes_to_draw.push_back(inode); + rr_nodes_to_draw.push_back(inode); - if (tptr->iswitch == OPEN) { //End of branch - draw_partial_route(rr_nodes_to_draw, g); - rr_nodes_to_draw.clear(); + if (tptr->iswitch == OPEN) { //End of branch + draw_partial_route(rr_nodes_to_draw, g); + rr_nodes_to_draw.clear(); - /* Skip the next segment */ - tptr = tptr->next; - if (tptr == nullptr) - break; - inode = tptr->index; - rr_nodes_to_draw.push_back(inode); - } + /* Skip the next segment */ + tptr = tptr->next; + if (tptr == nullptr) + break; + inode = tptr->index; + rr_nodes_to_draw.push_back(inode); + } - } /* End loop over traceback. */ + } /* End loop over traceback. */ - draw_partial_route(rr_nodes_to_draw, g); + draw_partial_route(rr_nodes_to_draw, g); } //Draws the set of rr_nodes specified, using the colors set in draw_state -void draw_partial_route(const std::vector& rr_nodes_to_draw, ezgl::renderer* g) { - t_draw_state* draw_state = get_draw_state_vars(); - auto& device_ctx = g_vpr_ctx.device(); - - 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 == GLOBAL) { - /* Allocate some temporary storage if it's not already available. */ - size_t width = device_ctx.grid.width(); - size_t height = device_ctx.grid.height(); - if (chanx_track.empty()) { - chanx_track = vtr::OffsetMatrix({{{1, width - 1}, {0, height - 1}}}); - } - - if (chany_track.empty()) { - chany_track = vtr::OffsetMatrix({{{0, width - 1}, {1, height - 1}}}); - } - - for (size_t i = 1; i < width - 1; i++) - for (size_t j = 0; j < height - 1; j++) - chanx_track[i][j] = (-1); - - for (size_t i = 0; i < width - 1; i++) - for (size_t j = 1; j < height - 1; j++) - chany_track[i][j] = (-1); - } - - for (size_t i = 1; i < rr_nodes_to_draw.size(); ++i) { - int inode = rr_nodes_to_draw[i]; - auto rr_type = device_ctx.rr_nodes[inode].type(); - - int prev_node = rr_nodes_to_draw[i - 1]; - auto prev_type = device_ctx.rr_nodes[prev_node].type(); - - auto iedge = find_edge(prev_node, inode); - auto switch_type = device_ctx.rr_nodes[prev_node].edge_switch(iedge); - - switch (rr_type) { - case OPIN: { - draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); - break; - } - case IPIN: { - draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); - if (device_ctx.rr_nodes[prev_node].type() == OPIN) { - draw_pin_to_pin(prev_node, inode, g); - } else { - draw_pin_to_chan_edge(inode, prev_node, g); - } - break; - } - case CHANX: { - if (draw_state->draw_route_type == GLOBAL) - chanx_track[device_ctx.rr_nodes[inode].xlow()][device_ctx.rr_nodes[inode].ylow()]++; - - int itrack = get_track_num(inode, chanx_track, chany_track); - draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); - - switch (prev_type) { - case CHANX: { - draw_chanx_to_chanx_edge(prev_node, inode, - itrack, switch_type, g); - break; - } - case CHANY: { - int prev_track = get_track_num(prev_node, chanx_track, - chany_track); - draw_chanx_to_chany_edge(inode, itrack, prev_node, - - prev_track, FROM_Y_TO_X, switch_type, g); - break; - } - case 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 CHANY: { - if (draw_state->draw_route_type == GLOBAL) - chany_track[device_ctx.rr_nodes[inode].xlow()][device_ctx.rr_nodes[inode].ylow()]++; - - int itrack = get_track_num(inode, chanx_track, chany_track); - draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); - - switch (prev_type) { - case CHANX: { - int prev_track = get_track_num(prev_node, chanx_track, - chany_track); - draw_chanx_to_chany_edge(prev_node, prev_track, inode, - itrack, FROM_X_TO_Y, switch_type, g); - break; - } - case CHANY: { - draw_chany_to_chany_edge(prev_node, inode, - itrack, switch_type, g); - break; - } - case 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; - } - } - } +void draw_partial_route(const std::vector &rr_nodes_to_draw, + ezgl::renderer *g) { + t_draw_state *draw_state = get_draw_state_vars(); + auto &device_ctx = g_vpr_ctx.device(); + + 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 == GLOBAL) { + /* Allocate some temporary storage if it's not already available. */ + size_t width = device_ctx.grid.width(); + size_t height = device_ctx.grid.height(); + if (chanx_track.empty()) { + chanx_track = vtr::OffsetMatrix( + { { { 1, width - 1 }, { 0, height - 1 } } }); + } + + if (chany_track.empty()) { + chany_track = vtr::OffsetMatrix( + { { { 0, width - 1 }, { 1, height - 1 } } }); + } + + for (size_t i = 1; i < width - 1; i++) + for (size_t j = 0; j < height - 1; j++) + chanx_track[i][j] = (-1); + + for (size_t i = 0; i < width - 1; i++) + for (size_t j = 1; j < height - 1; j++) + chany_track[i][j] = (-1); + } + + for (size_t i = 1; i < rr_nodes_to_draw.size(); ++i) { + int inode = rr_nodes_to_draw[i]; + auto rr_type = device_ctx.rr_nodes[inode].type(); + + int prev_node = rr_nodes_to_draw[i - 1]; + auto prev_type = device_ctx.rr_nodes[prev_node].type(); + + auto iedge = find_edge(prev_node, inode); + auto switch_type = device_ctx.rr_nodes[prev_node].edge_switch(iedge); + + switch (rr_type) { + case OPIN: { + draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); + break; + } + case IPIN: { + draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); + if (device_ctx.rr_nodes[prev_node].type() == OPIN) { + draw_pin_to_pin(prev_node, inode, g); + } else { + draw_pin_to_chan_edge(inode, prev_node, g); + } + break; + } + case CHANX: { + if (draw_state->draw_route_type == GLOBAL) + chanx_track[device_ctx.rr_nodes[inode].xlow()][device_ctx.rr_nodes[inode].ylow()]++; + + int itrack = get_track_num(inode, chanx_track, chany_track); + draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); + + switch (prev_type) { + case CHANX: { + draw_chanx_to_chanx_edge(prev_node, inode, itrack, switch_type, + g); + break; + } + case CHANY: { + int prev_track = get_track_num(prev_node, chanx_track, + chany_track); + draw_chanx_to_chany_edge(inode, itrack, prev_node, + + prev_track, FROM_Y_TO_X, switch_type, g); + break; + } + case 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 CHANY: { + if (draw_state->draw_route_type == GLOBAL) + chany_track[device_ctx.rr_nodes[inode].xlow()][device_ctx.rr_nodes[inode].ylow()]++; + + int itrack = get_track_num(inode, chanx_track, chany_track); + draw_rr_chan(inode, draw_state->draw_rr_node[inode].color, g); + + switch (prev_type) { + case CHANX: { + int prev_track = get_track_num(prev_node, chanx_track, + chany_track); + draw_chanx_to_chany_edge(prev_node, prev_track, inode, itrack, + FROM_X_TO_Y, switch_type, g); + break; + } + case CHANY: { + draw_chany_to_chany_edge(prev_node, inode, itrack, switch_type, + g); + break; + } + case 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; + } + } + } } -static 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. */ +static 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. */ - int i, j; - t_rr_type rr_type; - auto& device_ctx = g_vpr_ctx.device(); + int i, j; + t_rr_type rr_type; + auto &device_ctx = g_vpr_ctx.device(); - if (get_draw_state_vars()->draw_route_type == DETAILED) - return (device_ctx.rr_nodes[inode].ptc_num()); + if (get_draw_state_vars()->draw_route_type == DETAILED) + return (device_ctx.rr_nodes[inode].ptc_num()); - /* GLOBAL route stuff below. */ + /* GLOBAL route stuff below. */ - rr_type = device_ctx.rr_nodes[inode].type(); - i = device_ctx.rr_nodes[inode].xlow(); /* NB: Global rr graphs must have only unit */ - j = device_ctx.rr_nodes[inode].ylow(); /* length channel segments. */ + rr_type = device_ctx.rr_nodes[inode].type(); + i = device_ctx.rr_nodes[inode].xlow(); /* NB: Global rr graphs must have only unit */ + j = device_ctx.rr_nodes[inode].ylow(); /* length channel segments. */ - switch (rr_type) { - case CHANX: - return (chanx_track[i][j]); + switch (rr_type) { + case CHANX: + return (chanx_track[i][j]); - case CHANY: - return (chany_track[i][j]); + case CHANY: + return (chany_track[i][j]); - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in get_track_num: Unexpected node type %d for node %d.\n", rr_type, inode); - return OPEN; - } + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in get_track_num: Unexpected node type %d for node %d.\n", + rr_type, inode); + return OPEN; + } } /* This helper function determines whether a net has been highlighted. The highlighting @@ -2490,42 +2712,46 @@ static int get_track_num(int inode, const vtr::OffsetMatrix& chanx_track, c * fan-in/fan-out of a highlighted node. */ static bool draw_if_net_highlighted(ClusterNetId inet) { - t_draw_state* draw_state = get_draw_state_vars(); + t_draw_state *draw_state = get_draw_state_vars(); - if (draw_state->net_color[inet] != DEFAULT_RR_NODE_COLOR) { - return true; - } + if (draw_state->net_color[inet] != DEFAULT_RR_NODE_COLOR) { + return true; + } - return false; + return false; } /* 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, int hit_node) { - t_trace* tptr; - auto& cluster_ctx = g_vpr_ctx.clustering(); - 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()) { - for (tptr = route_ctx.trace[net_id].head; tptr != nullptr; tptr = tptr->next) { - if (draw_state->draw_rr_node[tptr->index].color == ezgl::MAGENTA) { - draw_state->net_color[net_id] = draw_state->draw_rr_node[tptr->index].color; - if (tptr->index == 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[tptr->index].color == ezgl::WHITE) { - // If node is de-selected. - draw_state->net_color[net_id] = ezgl::BLACK; - break; - } - } - } - application.update_message(message); +void highlight_nets(char *message, int hit_node) { + t_trace *tptr; + auto &cluster_ctx = g_vpr_ctx.clustering(); + 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()) { + for (tptr = route_ctx.trace[net_id].head; tptr != nullptr; + tptr = tptr->next) { + if (draw_state->draw_rr_node[tptr->index].color == ezgl::MAGENTA) { + draw_state->net_color[net_id] = + draw_state->draw_rr_node[tptr->index].color; + if (tptr->index == 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[tptr->index].color + == ezgl::WHITE) { + // If node is de-selected. + draw_state->net_color[net_id] = ezgl::BLACK; + break; + } + } + } + application.update_message(message); } /* If an rr_node has been clicked on, it will be either highlighted in MAGENTA, @@ -2533,44 +2759,56 @@ void highlight_nets(char* message, int hit_node) { * fan_in into the node in blue and fan_out from the node in red. If de-highlighted, * de-highlight its fan_in and fan_out. */ -void draw_highlight_fan_in_fan_out(const std::set& nodes) { - t_draw_state* draw_state = get_draw_state_vars(); - auto& device_ctx = g_vpr_ctx.device(); - - for (auto node : nodes) { - /* Highlight the fanout nodes in red. */ - for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[node].num_edges(); iedge < l; iedge++) { - int fanout_node = device_ctx.rr_nodes[node].edge_sink_node(iedge); - - if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA && draw_state->draw_rr_node[fanout_node].color != ezgl::MAGENTA) { - // If node is highlighted, highlight its fanout - draw_state->draw_rr_node[fanout_node].color = DRIVES_IT_COLOR; - draw_state->draw_rr_node[fanout_node].node_highlighted = true; - } else if (draw_state->draw_rr_node[node].color == ezgl::WHITE) { - // If node is de-highlighted, de-highlight its fanout - draw_state->draw_rr_node[fanout_node].color = DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[fanout_node].node_highlighted = false; - } - } - - /* Highlight the nodes that can fanin to this node in blue. */ - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[inode].num_edges(); iedge < l; iedge++) { - int fanout_node = device_ctx.rr_nodes[inode].edge_sink_node(iedge); - if (fanout_node == node) { - if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA && draw_state->draw_rr_node[inode].color != ezgl::MAGENTA) { - // If node is highlighted, highlight its fanin - draw_state->draw_rr_node[inode].color = ezgl::BLUE; - draw_state->draw_rr_node[inode].node_highlighted = true; - } else if (draw_state->draw_rr_node[node].color == ezgl::WHITE) { - // If node is de-highlighted, de-highlight its fanin - draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[inode].node_highlighted = false; - } - } - } - } - } +void draw_highlight_fan_in_fan_out(const std::set &nodes) { + t_draw_state *draw_state = get_draw_state_vars(); + auto &device_ctx = g_vpr_ctx.device(); + + for (auto node : nodes) { + /* Highlight the fanout nodes in red. */ + for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[node].num_edges(); + iedge < l; iedge++) { + int fanout_node = device_ctx.rr_nodes[node].edge_sink_node(iedge); + + if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA + && draw_state->draw_rr_node[fanout_node].color + != ezgl::MAGENTA) { + // If node is highlighted, highlight its fanout + draw_state->draw_rr_node[fanout_node].color = DRIVES_IT_COLOR; + draw_state->draw_rr_node[fanout_node].node_highlighted = true; + } else if (draw_state->draw_rr_node[node].color == ezgl::WHITE) { + // If node is de-highlighted, de-highlight its fanout + draw_state->draw_rr_node[fanout_node].color = + DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[fanout_node].node_highlighted = false; + } + } + + /* Highlight the nodes that can fanin to this node in blue. */ + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + for (t_edge_size iedge = 0, l = + device_ctx.rr_nodes[inode].num_edges(); iedge < l; + iedge++) { + int fanout_node = device_ctx.rr_nodes[inode].edge_sink_node( + iedge); + if (fanout_node == node) { + if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA + && draw_state->draw_rr_node[inode].color + != ezgl::MAGENTA) { + // If node is highlighted, highlight its fanin + draw_state->draw_rr_node[inode].color = ezgl::BLUE; + draw_state->draw_rr_node[inode].node_highlighted = true; + } else if (draw_state->draw_rr_node[node].color + == ezgl::WHITE) { + // If node is de-highlighted, de-highlight its fanin + draw_state->draw_rr_node[inode].color = + DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[inode].node_highlighted = + false; + } + } + } + } + } } /* This is a helper function for highlight_rr_nodes(). It determines whether @@ -2580,88 +2818,102 @@ void draw_highlight_fan_in_fan_out(const std::set& nodes) { * It returns the hit RR node's ID (or OPEN if no hit) */ static int draw_check_rr_node_hit(float click_x, float click_y) { - int hit_node = OPEN; - ezgl::rectangle bound_box; - - t_draw_coords* draw_coords = get_draw_coords_vars(); - auto& device_ctx = g_vpr_ctx.device(); - - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - switch (device_ctx.rr_nodes[inode].type()) { - case IPIN: - case OPIN: { - int i = device_ctx.rr_nodes[inode].xlow(); - int j = device_ctx.rr_nodes[inode].ylow(); - t_physical_tile_type_ptr type = device_ctx.grid[i][j].type; - int width_offset = device_ctx.grid[i][j].width_offset; - int height_offset = device_ctx.grid[i][j].height_offset; - int ipin = device_ctx.rr_nodes[inode].ptc_num(); - float xcen, ycen; - for (const e_side& iside : SIDES) { - // If pin exists on this side of the block, then get pin coordinates - if (type->pinloc[width_offset][height_offset][size_t(iside)][ipin]) { - draw_get_rr_pin_coords(inode, &xcen, &ycen, iside); - - // Now check if we clicked on this pin - if (click_x >= xcen - draw_coords->pin_size && click_x <= xcen + draw_coords->pin_size && click_y >= ycen - draw_coords->pin_size && click_y <= ycen + draw_coords->pin_size) { - hit_node = inode; - return hit_node; - } - } - } - break; - } - case SOURCE: - case SINK: { - float xcen, ycen; - draw_get_rr_src_sink_coords(device_ctx.rr_nodes[inode], &xcen, &ycen); - - // Now check if we clicked on this pin - if (click_x >= xcen - draw_coords->pin_size && click_x <= xcen + draw_coords->pin_size && click_y >= ycen - draw_coords->pin_size && click_y <= ycen + draw_coords->pin_size) { - hit_node = inode; - return hit_node; - } - break; - } - case CHANX: - case CHANY: { - bound_box = draw_get_rr_chan_bbox(inode); - - // Check if we clicked on this wire, with 30% - // tolerance outside its boundary - const float tolerance = 0.3; - if (click_x >= bound_box.left() - tolerance && click_x <= bound_box.right() + tolerance && click_y >= bound_box.bottom() - tolerance && click_y <= bound_box.top() + tolerance) { - hit_node = inode; - return hit_node; - } - break; - } - default: - break; - } - } - return hit_node; + int hit_node = OPEN; + ezgl::rectangle bound_box; + + t_draw_coords *draw_coords = get_draw_coords_vars(); + auto &device_ctx = g_vpr_ctx.device(); + + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + switch (device_ctx.rr_nodes[inode].type()) { + case IPIN: + case OPIN: { + int i = device_ctx.rr_nodes[inode].xlow(); + int j = device_ctx.rr_nodes[inode].ylow(); + t_physical_tile_type_ptr type = device_ctx.grid[i][j].type; + int width_offset = device_ctx.grid[i][j].width_offset; + int height_offset = device_ctx.grid[i][j].height_offset; + int ipin = device_ctx.rr_nodes[inode].ptc_num(); + float xcen, ycen; + for (const e_side &iside : SIDES) { + // If pin exists on this side of the block, then get pin coordinates + if (type->pinloc[width_offset][height_offset][size_t(iside)][ipin]) { + draw_get_rr_pin_coords(inode, &xcen, &ycen, iside); + + // Now check if we clicked on this pin + if (click_x >= xcen - draw_coords->pin_size + && click_x <= xcen + draw_coords->pin_size + && click_y >= ycen - draw_coords->pin_size + && click_y <= ycen + draw_coords->pin_size) { + hit_node = inode; + return hit_node; + } + } + } + break; + } + case SOURCE: + case SINK: { + float xcen, ycen; + draw_get_rr_src_sink_coords(device_ctx.rr_nodes[inode], &xcen, + &ycen); + + // Now check if we clicked on this pin + if (click_x >= xcen - draw_coords->pin_size + && click_x <= xcen + draw_coords->pin_size + && click_y >= ycen - draw_coords->pin_size + && click_y <= ycen + draw_coords->pin_size) { + hit_node = inode; + return hit_node; + } + break; + } + case CHANX: + case CHANY: { + bound_box = draw_get_rr_chan_bbox(inode); + + // Check if we clicked on this wire, with 30% + // tolerance outside its boundary + const float tolerance = 0.3; + if (click_x >= bound_box.left() - tolerance + && click_x <= bound_box.right() + tolerance + && click_y >= bound_box.bottom() - tolerance + && click_y <= bound_box.top() + tolerance) { + hit_node = inode; + return hit_node; + } + break; + } + default: + break; + } + } + return hit_node; } std::set draw_expand_non_configurable_rr_nodes(int from_node) { - std::set expanded_nodes; - draw_expand_non_configurable_rr_nodes_recurr(from_node, expanded_nodes); - return expanded_nodes; + std::set expanded_nodes; + draw_expand_non_configurable_rr_nodes_recurr(from_node, expanded_nodes); + return expanded_nodes; } -void draw_expand_non_configurable_rr_nodes_recurr(int from_node, std::set& expanded_nodes) { - auto& device_ctx = g_vpr_ctx.device(); +void draw_expand_non_configurable_rr_nodes_recurr(int from_node, + std::set &expanded_nodes) { + auto &device_ctx = g_vpr_ctx.device(); - expanded_nodes.insert(from_node); + expanded_nodes.insert(from_node); - for (t_edge_size iedge = 0; iedge < device_ctx.rr_nodes[from_node].num_edges(); ++iedge) { - bool edge_configurable = device_ctx.rr_nodes[from_node].edge_is_configurable(iedge); - int to_node = device_ctx.rr_nodes[from_node].edge_sink_node(iedge); + for (t_edge_size iedge = 0; + iedge < device_ctx.rr_nodes[from_node].num_edges(); ++iedge) { + bool edge_configurable = + device_ctx.rr_nodes[from_node].edge_is_configurable(iedge); + int to_node = device_ctx.rr_nodes[from_node].edge_sink_node(iedge); - if (!edge_configurable && !expanded_nodes.count(to_node)) { - draw_expand_non_configurable_rr_nodes_recurr(to_node, expanded_nodes); - } - } + if (!edge_configurable && !expanded_nodes.count(to_node)) { + draw_expand_non_configurable_rr_nodes_recurr(to_node, + expanded_nodes); + } + } } /* This routine is called when the routing resource graph is shown, and someone @@ -2670,18 +2922,18 @@ void draw_expand_non_configurable_rr_nodes_recurr(int from_node, std::set& * clicked upon, we highlight it in Magenta, and its fanout in red. */ static bool highlight_rr_nodes(float x, float y) { - t_draw_state* draw_state = get_draw_state_vars(); + t_draw_state *draw_state = get_draw_state_vars(); - if (draw_state->draw_rr_toggle == DRAW_NO_RR && !draw_state->show_nets) { - application.update_message(draw_state->default_message); - application.refresh_drawing(); - return false; //No rr shown - } + if (draw_state->draw_rr_toggle == DRAW_NO_RR && !draw_state->show_nets) { + application.update_message(draw_state->default_message); + application.refresh_drawing(); + return false; //No rr shown + } - // Check which rr_node (if any) was clicked on. - int hit_node = draw_check_rr_node_hit(x, y); + // Check which rr_node (if any) was clicked on. + int hit_node = draw_check_rr_node_hit(x, y); - return highlight_rr_nodes(hit_node); + return highlight_rr_nodes(hit_node); } # if defined(X11) && !defined(__MINGW32__) @@ -2690,201 +2942,209 @@ void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* std::string key(key_name); } # else -void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* /*key_name*/) { +void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, + char* /*key_name*/) { } # endif -void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, double y) { - // std::cout << "User clicked the "; - - if (event->button == 1) { - // std::cout << "left "; - - if (window_mode) { - //click on any two points to form new window rectangle bound - - if (!window_point_1_collected) { - //collect first point data - - window_point_1_collected = true; - point_1 = {x, y}; - } else { - //collect second point data - - //click on any two points to form new window rectangle bound - ezgl::point2d point_2 = {x, y}; - ezgl::rectangle current_window = (app->get_canvas(app->get_main_canvas_id()))->get_camera().get_world(); - - //calculate a rectangle with the same ratio based on the two clicks - double window_ratio = current_window.height() / current_window.width(); - double new_height = abs(point_1.y - point_2.y); - double new_width = new_height / window_ratio; - - //zoom in - ezgl::rectangle new_window = {point_1, {point_1.x + new_width, point_2.y}}; - (app->get_canvas(app->get_main_canvas_id()))->get_camera().set_world(new_window); - - //reset flags - window_mode = false; - window_point_1_collected = false; - } - app->refresh_drawing(); - } else { - // regular clicking mode - - /* This routine is called when the user clicks in the graphics area. * - * It determines if a clb was clicked on. If one was, it is * - * highlighted in green, it's fanin nets and clbs are highlighted in * - * blue and it's fanout is highlighted in red. If no clb was * - * clicked on (user clicked on white space) any old highlighting is * - * removed. Note that even though global nets are not drawn, their * - * fanins and fanouts are highlighted when you click on a block * - * attached to them. */ - - /* Control + mouse click to select multiple nets. */ - if (!(event->state & GDK_CONTROL_MASK)) - deselect_all(); - - //Check if we hit an rr node - // Note that we check this before checking for a block, since pins and routing may appear overtop of a multi-width/height block - if (highlight_rr_nodes(x, y)) { - return; //Selected an rr node - } - - highlight_blocks(x, y); - } - } - // else if (event->button == 2) - // std::cout << "middle "; - // else if (event->button == 3) - // std::cout << "right "; - - // std::cout << "mouse button at coordinates (" << x << "," << y << ") " << std::endl; +void act_on_mouse_press(ezgl::application *app, GdkEventButton *event, double x, + double y) { + // std::cout << "User clicked the "; + + if (event->button == 1) { + // std::cout << "left "; + + if (window_mode) { + //click on any two points to form new window rectangle bound + + if (!window_point_1_collected) { + //collect first point data + + window_point_1_collected = true; + point_1 = { x, y }; + } else { + //collect second point data + + //click on any two points to form new window rectangle bound + ezgl::point2d point_2 = { x, y }; + ezgl::rectangle current_window = (app->get_canvas( + app->get_main_canvas_id()))->get_camera().get_world(); + + //calculate a rectangle with the same ratio based on the two clicks + double window_ratio = current_window.height() + / current_window.width(); + double new_height = abs(point_1.y - point_2.y); + double new_width = new_height / window_ratio; + + //zoom in + ezgl::rectangle new_window = { point_1, { point_1.x + new_width, + point_2.y } }; + (app->get_canvas(app->get_main_canvas_id()))->get_camera().set_world( + new_window); + + //reset flags + window_mode = false; + window_point_1_collected = false; + } + app->refresh_drawing(); + } else { + // regular clicking mode + + /* This routine is called when the user clicks in the graphics area. * + * It determines if a clb was clicked on. If one was, it is * + * highlighted in green, it's fanin nets and clbs are highlighted in * + * blue and it's fanout is highlighted in red. If no clb was * + * clicked on (user clicked on white space) any old highlighting is * + * removed. Note that even though global nets are not drawn, their * + * fanins and fanouts are highlighted when you click on a block * + * attached to them. */ + + /* Control + mouse click to select multiple nets. */ + if (!(event->state & GDK_CONTROL_MASK)) + deselect_all(); + + //Check if we hit an rr node + // Note that we check this before checking for a block, since pins and routing may appear overtop of a multi-width/height block + if (highlight_rr_nodes(x, y)) { + return; //Selected an rr node + } + + highlight_blocks(x, y); + } + } + // else if (event->button == 2) + // std::cout << "middle "; + // else if (event->button == 3) + // std::cout << "right "; + + // std::cout << "mouse button at coordinates (" << x << "," << y << ") " << std::endl; } -void act_on_mouse_move(ezgl::application* app, GdkEventButton* event, double x, double y) { - // std::cout << "Mouse move at coordinates (" << x << "," << y << ") "<< std::endl; - - // user has clicked the window button, in window mode - if (window_point_1_collected) { - // draw a grey, dashed-line box to indicate the zoom-in region - app->refresh_drawing(); - ezgl::renderer* g = app->get_renderer(); - g->set_line_dash(ezgl::line_dash::asymmetric_5_3); - g->set_color(blk_GREY); - g->set_line_width(2); - g->draw_rectangle(point_1, {x, y}); - return; - } - - // user has not clicked the window button, in regular mode - t_draw_state* draw_state = get_draw_state_vars(); - - if (draw_state->draw_rr_toggle != DRAW_NO_RR) { - int hit_node = draw_check_rr_node_hit(x, y); - - if (hit_node != OPEN) { - //Update message - - std::string info = describe_rr_node(hit_node); - std::string msg = vtr::string_fmt("Moused over %s", info.c_str()); - app->update_message(msg.c_str()); - } else { - if (!rr_highlight_message.empty()) { - app->update_message(rr_highlight_message.c_str()); - } else { - app->update_message(draw_state->default_message); - } - } - } - event = event; // just for hiding warning message +void act_on_mouse_move(ezgl::application *app, GdkEventButton *event, double x, + double y) { + // std::cout << "Mouse move at coordinates (" << x << "," << y << ") "<< std::endl; + + // user has clicked the window button, in window mode + if (window_point_1_collected) { + // draw a grey, dashed-line box to indicate the zoom-in region + app->refresh_drawing(); + ezgl::renderer *g = app->get_renderer(); + g->set_line_dash(ezgl::line_dash::asymmetric_5_3); + g->set_color(blk_GREY); + g->set_line_width(2); + g->draw_rectangle(point_1, { x, y }); + return; + } + + // user has not clicked the window button, in regular mode + t_draw_state *draw_state = get_draw_state_vars(); + + if (draw_state->draw_rr_toggle != DRAW_NO_RR) { + int hit_node = draw_check_rr_node_hit(x, y); + + if (hit_node != OPEN) { + //Update message + + std::string info = describe_rr_node(hit_node); + std::string msg = vtr::string_fmt("Moused over %s", info.c_str()); + app->update_message(msg.c_str()); + } else { + if (!rr_highlight_message.empty()) { + app->update_message(rr_highlight_message.c_str()); + } else { + app->update_message(draw_state->default_message); + } + } + } + event = event; // just for hiding warning message } -void draw_highlight_blocks_color(t_logical_block_type_ptr type, ClusterBlockId blk_id) { - int k, iclass; - ClusterBlockId fanblk; - - t_draw_state* draw_state = get_draw_state_vars(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - - for (k = 0; k < type->pb_type->num_pins; k++) { /* Each pin on a CLB */ - ClusterNetId net_id = cluster_ctx.clb_nlist.block_net(blk_id, k); - - if (net_id == ClusterNetId::INVALID()) - continue; - - auto physical_tile = physical_tile_type(blk_id); - int physical_pin = get_physical_pin(physical_tile, type, k); - - iclass = physical_tile->pin_class[physical_pin]; - - if (physical_tile->class_inf[iclass].type == DRIVER) { /* Fanout */ - if (draw_state->block_color(blk_id) == SELECTED_COLOR) { - /* If block already highlighted, de-highlight the fanout. (the deselect case)*/ - draw_state->net_color[net_id] = ezgl::BLACK; - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); - draw_reset_blk_color(fanblk); - } - } else { - /* Highlight the fanout */ - draw_state->net_color[net_id] = DRIVES_IT_COLOR; - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); - draw_state->set_block_color(fanblk, DRIVES_IT_COLOR); - } - } - } else { /* This net is fanin to the block. */ - if (draw_state->block_color(blk_id) == SELECTED_COLOR) { - /* If block already highlighted, de-highlight the fanin. (the deselect case)*/ - draw_state->net_color[net_id] = ezgl::BLACK; - fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ - draw_reset_blk_color(fanblk); - } else { - /* Highlight the fanin */ - draw_state->net_color[net_id] = DRIVEN_BY_IT_COLOR; - fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ - draw_state->set_block_color(fanblk, DRIVEN_BY_IT_COLOR); - } - } - } - - if (draw_state->block_color(blk_id) == SELECTED_COLOR) { - /* If block already highlighted, de-highlight the selected block. */ - draw_reset_blk_color(blk_id); - } else { - /* Highlight the selected block. */ - draw_state->set_block_color(blk_id, SELECTED_COLOR); - } +void draw_highlight_blocks_color(t_logical_block_type_ptr type, + ClusterBlockId blk_id) { + int k, iclass; + ClusterBlockId fanblk; + + t_draw_state *draw_state = get_draw_state_vars(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + + for (k = 0; k < type->pb_type->num_pins; k++) { /* Each pin on a CLB */ + ClusterNetId net_id = cluster_ctx.clb_nlist.block_net(blk_id, k); + + if (net_id == ClusterNetId::INVALID()) + continue; + + auto physical_tile = physical_tile_type(blk_id); + int physical_pin = get_physical_pin(physical_tile, type, k); + + iclass = physical_tile->pin_class[physical_pin]; + + if (physical_tile->class_inf[iclass].type == DRIVER) { /* Fanout */ + if (draw_state->block_color(blk_id) == SELECTED_COLOR) { + /* If block already highlighted, de-highlight the fanout. (the deselect case)*/ + draw_state->net_color[net_id] = ezgl::BLACK; + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); + draw_reset_blk_color(fanblk); + } + } else { + /* Highlight the fanout */ + draw_state->net_color[net_id] = DRIVES_IT_COLOR; + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); + draw_state->set_block_color(fanblk, DRIVES_IT_COLOR); + } + } + } else { /* This net is fanin to the block. */ + if (draw_state->block_color(blk_id) == SELECTED_COLOR) { + /* If block already highlighted, de-highlight the fanin. (the deselect case)*/ + draw_state->net_color[net_id] = ezgl::BLACK; + fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ + draw_reset_blk_color(fanblk); + } else { + /* Highlight the fanin */ + draw_state->net_color[net_id] = DRIVEN_BY_IT_COLOR; + fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ + draw_state->set_block_color(fanblk, DRIVEN_BY_IT_COLOR); + } + } + } + + if (draw_state->block_color(blk_id) == SELECTED_COLOR) { + /* If block already highlighted, de-highlight the selected block. */ + draw_reset_blk_color(blk_id); + } else { + /* Highlight the selected block. */ + draw_state->set_block_color(blk_id, SELECTED_COLOR); + } } void deselect_all() { - // Sets the color of all clbs, nets and rr_nodes to the default. - // as well as clearing the highlighed sub-block - - t_draw_state* draw_state = get_draw_state_vars(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& device_ctx = g_vpr_ctx.device(); - - /* Create some colour highlighting */ - for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { - if (blk_id != ClusterBlockId::INVALID()) - draw_reset_blk_color(blk_id); - } - - for (auto net_id : cluster_ctx.clb_nlist.nets()) - draw_state->net_color[net_id] = ezgl::BLACK; - - for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { - draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[i].node_highlighted = false; - } - get_selected_sub_block_info().clear(); + // Sets the color of all clbs, nets and rr_nodes to the default. + // as well as clearing the highlighed sub-block + + t_draw_state *draw_state = get_draw_state_vars(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &device_ctx = g_vpr_ctx.device(); + + /* Create some colour highlighting */ + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + if (blk_id != ClusterBlockId::INVALID()) + draw_reset_blk_color(blk_id); + } + + for (auto net_id : cluster_ctx.clb_nlist.nets()) + draw_state->net_color[net_id] = ezgl::BLACK; + + for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { + draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[i].node_highlighted = false; + } + get_selected_sub_block_info().clear(); } static void draw_reset_blk_color(ClusterBlockId blk_id) { - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->reset_block_color(blk_id); + t_draw_state *draw_state = get_draw_state_vars(); + draw_state->reset_block_color(blk_id); } /** @@ -2896,23 +3156,27 @@ static void draw_reset_blk_color(ClusterBlockId blk_id) { * A 'relative_position' of 1. draws the triangle centered at 'end'. * Fractional values draw the triangle along the line */ -void draw_triangle_along_line(ezgl::renderer* g, ezgl::point2d start, ezgl::point2d end, float relative_position, float arrow_size) { - VTR_ASSERT(relative_position >= 0. && relative_position <= 1.); - float xdelta = end.x - start.x; - float ydelta = end.y - start.y; +void draw_triangle_along_line(ezgl::renderer *g, ezgl::point2d start, + ezgl::point2d end, float relative_position, float arrow_size) { + VTR_ASSERT(relative_position >= 0. && relative_position <= 1.); + float xdelta = end.x - start.x; + float ydelta = end.y - start.y; - float xtri = start.x + xdelta * relative_position; - float ytri = start.y + ydelta * relative_position; + float xtri = start.x + xdelta * relative_position; + float ytri = start.y + ydelta * relative_position; - draw_triangle_along_line(g, xtri, ytri, start.x, end.x, start.y, end.y, arrow_size); + draw_triangle_along_line(g, xtri, ytri, start.x, end.x, start.y, end.y, + arrow_size); } /* Draws a triangle with it's center at loc, and of length & width * arrow_size, rotated such that it points in the direction * of the directed line segment start -> end. */ -void draw_triangle_along_line(ezgl::renderer* g, ezgl::point2d loc, ezgl::point2d start, ezgl::point2d end, float arrow_size) { - draw_triangle_along_line(g, loc.x, loc.y, start.x, end.x, start.y, end.y, arrow_size); +void draw_triangle_along_line(ezgl::renderer *g, ezgl::point2d loc, + ezgl::point2d start, ezgl::point2d end, float arrow_size) { + draw_triangle_along_line(g, loc.x, loc.y, start.x, end.x, start.y, end.y, + arrow_size); } /** @@ -2923,1430 +3187,1618 @@ void draw_triangle_along_line(ezgl::renderer* g, ezgl::point2d loc, ezgl::point2 * Note that the parameters are in a strange order */ -void draw_triangle_along_line(ezgl::renderer* g, float xend, float yend, float x1, float x2, float y1, float y2, float arrow_size) { - float switch_rad = arrow_size / 2; - float xdelta, ydelta; - float magnitude; - float xunit, yunit; - float xbaseline, ybaseline; +void draw_triangle_along_line(ezgl::renderer *g, float xend, float yend, + float x1, float x2, float y1, float y2, float arrow_size) { + float switch_rad = arrow_size / 2; + float xdelta, ydelta; + float magnitude; + float xunit, yunit; + float xbaseline, ybaseline; - std::vector poly; + std::vector poly; - xdelta = x2 - x1; - ydelta = y2 - y1; - magnitude = sqrt(xdelta * xdelta + ydelta * ydelta); + xdelta = x2 - x1; + ydelta = y2 - y1; + magnitude = sqrt(xdelta * xdelta + ydelta * ydelta); - xunit = xdelta / magnitude; - yunit = ydelta / magnitude; + xunit = xdelta / magnitude; + yunit = ydelta / magnitude; - poly.push_back({xend + xunit * switch_rad, yend + yunit * switch_rad}); - xbaseline = xend - xunit * switch_rad; - ybaseline = yend - yunit * switch_rad; - poly.push_back({xbaseline + yunit * switch_rad, ybaseline - xunit * switch_rad}); - poly.push_back({xbaseline - yunit * switch_rad, ybaseline + xunit * switch_rad}); + poly.push_back( { xend + xunit * switch_rad, yend + yunit * switch_rad }); + xbaseline = xend - xunit * switch_rad; + ybaseline = yend - yunit * switch_rad; + poly.push_back( + { xbaseline + yunit * switch_rad, ybaseline - xunit * switch_rad }); + poly.push_back( + { xbaseline - yunit * switch_rad, ybaseline + xunit * switch_rad }); - g->fill_poly(poly); + g->fill_poly(poly); } -static void draw_pin_to_chan_edge(int pin_node, int 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 t_rr_node& pin_rr = device_ctx.rr_nodes[pin_node]; - const t_rr_node& chan_rr = device_ctx.rr_nodes[chan_node]; - - const t_grid_tile& grid_tile = device_ctx.grid[pin_rr.xlow()][pin_rr.ylow()]; - t_physical_tile_type_ptr grid_type = grid_tile.type; - - 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 - * However, we can infer which side is actually used by the driver based on the - * coordinates of the channel node. - * In principle, in a regular rr_graph that can pass check_rr_graph() function, - * the coordinates should follow the illustration: - * - * +----------+ - * | CHANX | - * | [x][y] | - * +----------+ - * +----------+ +----------+ +--------+ - * | | | | | | - * | CHANY | | Grid | | CHANY | - * | [x-1][y] | | [x][y] | | [x][y] | - * | | | | | | - * +----------+ +----------+ +--------+ - * +----------+ - * | CHANX | - * | [x][y-1] | - * +----------+ - * - * - * Therefore, when there are multiple side: - * - a TOP side node is considered when the ylow of CHANX >= ylow of the node - * - a BOTTOM side node is considered when the ylow of CHANX <= ylow - 1 of the node - * - a RIGHT side node is considered when the xlow of CHANY >= xlow of the node - * - a LEFT side node is considered when the xlow of CHANY <= xlow - 1 of the node - * - * Note: ylow == yhigh for CHANX and xlow == xhigh for CHANY - * - * Note: Similar rules are applied for grid that has width > 1 and height > 1 - * This is because (xlow, ylow) or (xhigh, yhigh) of the node follows - * the actual offset of the pin in the context of grid width and height - */ - std::vector pin_candidate_sides; - for (const e_side& pin_candidate_side : SIDES) { - if ((pin_rr.is_node_on_specific_side(pin_candidate_side)) - && (grid_type->pinloc[grid_tile.width_offset][grid_tile.height_offset][pin_candidate_side][pin_rr.pin_num()])) { - pin_candidate_sides.push_back(pin_candidate_side); - } - } - /* Only 1 side will be picked in the end - * Any rr_node of a grid should have at least 1 side!!! - */ - e_side pin_side = NUM_SIDES; - if (1 == pin_candidate_sides.size()) { - pin_side = pin_candidate_sides[0]; - } else { - VTR_ASSERT(1 < pin_candidate_sides.size()); - if (CHANX == chan_rr.type() && pin_rr.ylow() <= chan_rr.ylow()) { - pin_side = TOP; - } else if (CHANX == chan_rr.type() && pin_rr.ylow() - 1 >= chan_rr.ylow()) { - pin_side = BOTTOM; - } else if (CHANY == chan_rr.type() && pin_rr.xlow() <= chan_rr.xlow()) { - pin_side = RIGHT; - } else if (CHANY == chan_rr.type() && pin_rr.xlow() - 1 >= chan_rr.xlow()) { - pin_side = LEFT; - } - /* The inferred side must be in the list of sides of the pin rr_node!!! */ - VTR_ASSERT(pin_candidate_sides.end() != std::find(pin_candidate_sides.begin(), pin_candidate_sides.end(), pin_side)); - } - /* Sanity check */ - VTR_ASSERT(NUM_SIDES != pin_side); - - /* 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 - * - For the pin locates below/left to the grid (at the bottom/left side), - * a negative offset (-ve) is required - * - * y - * ^ +-----+ --- - * | | PIN | ^ - * | | | offset - * | | | v - * | +-----------+-----+----------+ - * | | |<- offset ->| - * | |<-offset->| +------------+ - * | +----------+ Grid | PIN | - * | | PIN | +------------+ - * | +----------+ | - * | | | - * | +---+-----+------------------+ - * | ^ | | - * | offset | PIN | - * | v | | - * | ----+-----+ - * +------------------------------------------------------------>x - */ - float draw_pin_offset; - if (TOP == pin_side || RIGHT == pin_side) { - draw_pin_offset = draw_coords->pin_size; - } else { - VTR_ASSERT(BOTTOM == pin_side || LEFT == pin_side); - draw_pin_offset = -draw_coords->pin_size; - } - - draw_get_rr_pin_coords(pin_node, &x1, &y1, pin_side); - - ezgl::rectangle chan_bbox = draw_get_rr_chan_bbox(chan_node); - - float x2 = 0, y2 = 0; - switch (chan_rr.type()) { - case CHANX: { - y1 += draw_pin_offset; - y2 = chan_bbox.bottom(); - x2 = x1; - if (is_opin(pin_rr.pin_num(), grid_type)) { - if (chan_rr.direction() == INC_DIRECTION) { - x2 = chan_bbox.left(); - } else if (chan_rr.direction() == DEC_DIRECTION) { - x2 = chan_bbox.right(); - } - } - break; - } - case CHANY: { - x1 += draw_pin_offset; - x2 = chan_bbox.left(); - y2 = y1; - if (is_opin(pin_rr.pin_num(), grid_type)) { - if (chan_rr.direction() == INC_DIRECTION) { - y2 = chan_bbox.bottom(); - } else if (chan_rr.direction() == DEC_DIRECTION) { - y2 = chan_bbox.top(); - } - } - break; - } - default: { - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_pin_to_chan_edge: Invalid channel node %d.\n", chan_node); - } - } - g->draw_line({x1, y1}, {x2, y2}); - - //don't draw the ex, or triangle unless zoomed in really far - if (chan_rr.direction() == BI_DIRECTION || !is_opin(pin_rr.pin_num(), grid_type)) { - draw_x(x2, y2, 0.7 * draw_coords->pin_size, g); - } else { - float xend = x2 + (x1 - x2) / 10.; - float yend = y2 + (y1 - y2) / 10.; - draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); - } +static void draw_pin_to_chan_edge(int pin_node, int 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 t_rr_node &pin_rr = device_ctx.rr_nodes[pin_node]; + const t_rr_node &chan_rr = device_ctx.rr_nodes[chan_node]; + + const t_grid_tile &grid_tile = device_ctx.grid[pin_rr.xlow()][pin_rr.ylow()]; + t_physical_tile_type_ptr grid_type = grid_tile.type; + + 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 + * However, we can infer which side is actually used by the driver based on the + * coordinates of the channel node. + * In principle, in a regular rr_graph that can pass check_rr_graph() function, + * the coordinates should follow the illustration: + * + * +----------+ + * | CHANX | + * | [x][y] | + * +----------+ + * +----------+ +----------+ +--------+ + * | | | | | | + * | CHANY | | Grid | | CHANY | + * | [x-1][y] | | [x][y] | | [x][y] | + * | | | | | | + * +----------+ +----------+ +--------+ + * +----------+ + * | CHANX | + * | [x][y-1] | + * +----------+ + * + * + * Therefore, when there are multiple side: + * - a TOP side node is considered when the ylow of CHANX >= ylow of the node + * - a BOTTOM side node is considered when the ylow of CHANX <= ylow - 1 of the node + * - a RIGHT side node is considered when the xlow of CHANY >= xlow of the node + * - a LEFT side node is considered when the xlow of CHANY <= xlow - 1 of the node + * + * Note: ylow == yhigh for CHANX and xlow == xhigh for CHANY + * + * Note: Similar rules are applied for grid that has width > 1 and height > 1 + * This is because (xlow, ylow) or (xhigh, yhigh) of the node follows + * the actual offset of the pin in the context of grid width and height + */ + std::vector pin_candidate_sides; + for (const e_side &pin_candidate_side : SIDES) { + if ((pin_rr.is_node_on_specific_side(pin_candidate_side)) + && (grid_type->pinloc[grid_tile.width_offset][grid_tile.height_offset][pin_candidate_side][pin_rr.pin_num()])) { + pin_candidate_sides.push_back(pin_candidate_side); + } + } + /* Only 1 side will be picked in the end + * Any rr_node of a grid should have at least 1 side!!! + */ + e_side pin_side = NUM_SIDES; + if (1 == pin_candidate_sides.size()) { + pin_side = pin_candidate_sides[0]; + } else { + VTR_ASSERT(1 < pin_candidate_sides.size()); + if (CHANX == chan_rr.type() && pin_rr.ylow() <= chan_rr.ylow()) { + pin_side = TOP; + } else if (CHANX == chan_rr.type() + && pin_rr.ylow() - 1 >= chan_rr.ylow()) { + pin_side = BOTTOM; + } else if (CHANY == chan_rr.type() && pin_rr.xlow() <= chan_rr.xlow()) { + pin_side = RIGHT; + } else if (CHANY == chan_rr.type() + && pin_rr.xlow() - 1 >= chan_rr.xlow()) { + pin_side = LEFT; + } + /* The inferred side must be in the list of sides of the pin rr_node!!! */ + VTR_ASSERT( + pin_candidate_sides.end() + != std::find(pin_candidate_sides.begin(), + pin_candidate_sides.end(), pin_side)); + } + /* Sanity check */ + VTR_ASSERT(NUM_SIDES != pin_side); + + /* 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 + * - For the pin locates below/left to the grid (at the bottom/left side), + * a negative offset (-ve) is required + * + * y + * ^ +-----+ --- + * | | PIN | ^ + * | | | offset + * | | | v + * | +-----------+-----+----------+ + * | | |<- offset ->| + * | |<-offset->| +------------+ + * | +----------+ Grid | PIN | + * | | PIN | +------------+ + * | +----------+ | + * | | | + * | +---+-----+------------------+ + * | ^ | | + * | offset | PIN | + * | v | | + * | ----+-----+ + * +------------------------------------------------------------>x + */ + float draw_pin_offset; + if (TOP == pin_side || RIGHT == pin_side) { + draw_pin_offset = draw_coords->pin_size; + } else { + VTR_ASSERT(BOTTOM == pin_side || LEFT == pin_side); + draw_pin_offset = -draw_coords->pin_size; + } + + draw_get_rr_pin_coords(pin_node, &x1, &y1, pin_side); + + ezgl::rectangle chan_bbox = draw_get_rr_chan_bbox(chan_node); + + float x2 = 0, y2 = 0; + switch (chan_rr.type()) { + case CHANX: { + y1 += draw_pin_offset; + y2 = chan_bbox.bottom(); + x2 = x1; + if (is_opin(pin_rr.pin_num(), grid_type)) { + if (chan_rr.direction() == INC_DIRECTION) { + x2 = chan_bbox.left(); + } else if (chan_rr.direction() == DEC_DIRECTION) { + x2 = chan_bbox.right(); + } + } + break; + } + case CHANY: { + x1 += draw_pin_offset; + x2 = chan_bbox.left(); + y2 = y1; + if (is_opin(pin_rr.pin_num(), grid_type)) { + if (chan_rr.direction() == INC_DIRECTION) { + y2 = chan_bbox.bottom(); + } else if (chan_rr.direction() == DEC_DIRECTION) { + y2 = chan_bbox.top(); + } + } + break; + } + default: { + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_pin_to_chan_edge: Invalid channel node %d.\n", + chan_node); + } + } + g->draw_line( { x1, y1 }, { x2, y2 }); + + //don't draw the ex, or triangle unless zoomed in really far + if (chan_rr.direction() == BI_DIRECTION + || !is_opin(pin_rr.pin_num(), grid_type)) { + draw_x(x2, y2, 0.7 * draw_coords->pin_size, g); + } else { + float xend = x2 + (x1 - x2) / 10.; + float yend = y2 + (y1 - y2) / 10.; + draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); + } } -static void draw_pin_to_pin(int opin_node, int ipin_node, ezgl::renderer* g) { - /* This routine draws an edge from the opin rr node to the ipin rr node */ - auto& device_ctx = g_vpr_ctx.device(); - VTR_ASSERT(device_ctx.rr_nodes[opin_node].type() == OPIN); - VTR_ASSERT(device_ctx.rr_nodes[ipin_node].type() == IPIN); - - /* FIXME: May use a smarter strategy - * Currently, we use the last side found for both OPIN and IPIN - * when draw the direct connection between the two nodes - * Note: tried first side but see missing connections - */ - float x1 = 0, y1 = 0; - std::vector opin_candidate_sides; - for (const e_side& opin_candidate_side : SIDES) { - if (device_ctx.rr_nodes[opin_node].is_node_on_specific_side(opin_candidate_side)) { - opin_candidate_sides.push_back(opin_candidate_side); - } - } - VTR_ASSERT(1 <= opin_candidate_sides.size()); - draw_get_rr_pin_coords(opin_node, &x1, &y1, opin_candidate_sides.back()); - - float x2 = 0, y2 = 0; - std::vector ipin_candidate_sides; - for (const e_side& ipin_candidate_side : SIDES) { - if (device_ctx.rr_nodes[ipin_node].is_node_on_specific_side(ipin_candidate_side)) { - ipin_candidate_sides.push_back(ipin_candidate_side); - } - } - VTR_ASSERT(1 <= ipin_candidate_sides.size()); - draw_get_rr_pin_coords(ipin_node, &x2, &y2, ipin_candidate_sides.back()); - - g->draw_line({x1, y1}, {x2, y2}); - - float xend = x2 + (x1 - x2) / 10.; - float yend = y2 + (y1 - y2) / 10.; - draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); +static void draw_pin_to_pin(int opin_node, int ipin_node, ezgl::renderer *g) { + /* This routine draws an edge from the opin rr node to the ipin rr node */ + auto &device_ctx = g_vpr_ctx.device(); + VTR_ASSERT(device_ctx.rr_nodes[opin_node].type() == OPIN); + VTR_ASSERT(device_ctx.rr_nodes[ipin_node].type() == IPIN); + + /* FIXME: May use a smarter strategy + * Currently, we use the last side found for both OPIN and IPIN + * when draw the direct connection between the two nodes + * Note: tried first side but see missing connections + */ + float x1 = 0, y1 = 0; + std::vector opin_candidate_sides; + for (const e_side &opin_candidate_side : SIDES) { + if (device_ctx.rr_nodes[opin_node].is_node_on_specific_side( + opin_candidate_side)) { + opin_candidate_sides.push_back(opin_candidate_side); + } + } + VTR_ASSERT(1 <= opin_candidate_sides.size()); + draw_get_rr_pin_coords(opin_node, &x1, &y1, opin_candidate_sides.back()); + + float x2 = 0, y2 = 0; + std::vector ipin_candidate_sides; + for (const e_side &ipin_candidate_side : SIDES) { + if (device_ctx.rr_nodes[ipin_node].is_node_on_specific_side( + ipin_candidate_side)) { + ipin_candidate_sides.push_back(ipin_candidate_side); + } + } + VTR_ASSERT(1 <= ipin_candidate_sides.size()); + draw_get_rr_pin_coords(ipin_node, &x2, &y2, ipin_candidate_sides.back()); + + g->draw_line( { x1, y1 }, { x2, y2 }); + + float xend = x2 + (x1 - x2) / 10.; + float yend = y2 + (y1 - y2) / 10.; + draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); } -static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer* g) { - auto& device_ctx = g_vpr_ctx.device(); +static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer *g) { + auto &device_ctx = g_vpr_ctx.device(); - float x1 = 0, y1 = 0; - /* Draw the line for each ipin on different sides */ - for (const e_side& pin_side : SIDES) { - if (!device_ctx.rr_nodes[ipin_node].is_node_on_specific_side(pin_side)) { - continue; - } + float x1 = 0, y1 = 0; + /* Draw the line for each ipin on different sides */ + for (const e_side &pin_side : SIDES) { + if (!device_ctx.rr_nodes[ipin_node].is_node_on_specific_side( + pin_side)) { + continue; + } - draw_get_rr_pin_coords(ipin_node, &x1, &y1, pin_side); + draw_get_rr_pin_coords(ipin_node, &x1, &y1, pin_side); - float x2 = 0, y2 = 0; - draw_get_rr_src_sink_coords(device_ctx.rr_nodes[sink_node], &x2, &y2); + float x2 = 0, y2 = 0; + draw_get_rr_src_sink_coords(device_ctx.rr_nodes[sink_node], &x2, &y2); - g->draw_line({x1, y1}, {x2, y2}); + g->draw_line( { x1, y1 }, { x2, y2 }); - float xend = x2 + (x1 - x2) / 10.; - float yend = y2 + (y1 - y2) / 10.; - draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); - } + float xend = x2 + (x1 - x2) / 10.; + float yend = y2 + (y1 - y2) / 10.; + draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); + } } -static void draw_source_to_pin(int source_node, int opin_node, ezgl::renderer* g) { - auto& device_ctx = g_vpr_ctx.device(); +static void draw_source_to_pin(int source_node, int opin_node, + ezgl::renderer *g) { + auto &device_ctx = g_vpr_ctx.device(); - float x1 = 0, y1 = 0; - draw_get_rr_src_sink_coords(device_ctx.rr_nodes[source_node], &x1, &y1); + float x1 = 0, y1 = 0; + draw_get_rr_src_sink_coords(device_ctx.rr_nodes[source_node], &x1, &y1); - /* Draw the line for each ipin on different sides */ - for (const e_side& pin_side : SIDES) { - if (!device_ctx.rr_nodes[opin_node].is_node_on_specific_side(pin_side)) { - continue; - } + /* Draw the line for each ipin on different sides */ + for (const e_side &pin_side : SIDES) { + if (!device_ctx.rr_nodes[opin_node].is_node_on_specific_side( + pin_side)) { + continue; + } - float x2 = 0, y2 = 0; - draw_get_rr_pin_coords(opin_node, &x2, &y2, pin_side); + float x2 = 0, y2 = 0; + draw_get_rr_pin_coords(opin_node, &x2, &y2, pin_side); - g->draw_line({x1, y1}, {x2, y2}); + g->draw_line( { x1, y1 }, { x2, y2 }); - float xend = x2 + (x1 - x2) / 10.; - float yend = y2 + (y1 - y2) / 10.; - draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); - } + float xend = x2 + (x1 - x2) / 10.; + float yend = y2 + (y1 - y2) / 10.; + draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); + } } -static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, float height, int size, ezgl::renderer* g) { - g->set_color(ezgl::YELLOW); - auto bounds = draw_mux(origin, orientation, height, g); +static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, + float height, int size, ezgl::renderer *g) { + g->set_color(ezgl::YELLOW); + auto bounds = draw_mux(origin, orientation, height, g); - g->set_color(ezgl::BLACK); - g->draw_text(bounds.center(), std::to_string(size), bounds.width(), bounds.height()); + g->set_color(ezgl::BLACK); + g->draw_text(bounds.center(), std::to_string(size), bounds.width(), + bounds.height()); } //Draws a mux -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, ezgl::renderer* g) { - return draw_mux(origin, orientation, height, 0.4 * height, 0.6, g); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, + float height, ezgl::renderer *g) { + return draw_mux(origin, orientation, height, 0.4 * height, 0.6, g); } //Draws a mux, height/width define the bounding box, scale [0.,1.] controls the slope of the muxes sides -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, float width, float scale, ezgl::renderer* g) { - std::vector mux_polygon; - - switch (orientation) { - case TOP: - //Clock-wise from bottom left - mux_polygon.push_back({origin.x - height / 2, origin.y - width / 2}); - mux_polygon.push_back({origin.x - (scale * height) / 2, origin.y + width / 2}); - mux_polygon.push_back({origin.x + (scale * height) / 2, origin.y + width / 2}); - mux_polygon.push_back({origin.x + height / 2, origin.y - width / 2}); - break; - case BOTTOM: - //Clock-wise from bottom left - mux_polygon.push_back({origin.x - (scale * height) / 2, origin.y - width / 2}); - mux_polygon.push_back({origin.x - height / 2, origin.y + width / 2}); - mux_polygon.push_back({origin.x + height / 2, origin.y + width / 2}); - mux_polygon.push_back({origin.x + (scale * height) / 2, origin.y - width / 2}); - break; - case LEFT: - //Clock-wise from bottom left - mux_polygon.push_back({origin.x - width / 2, origin.y - (scale * height) / 2}); - mux_polygon.push_back({origin.x - width / 2, origin.y + (scale * height) / 2}); - mux_polygon.push_back({origin.x + width / 2, origin.y + height / 2}); - mux_polygon.push_back({origin.x + width / 2, origin.y - height / 2}); - break; - case RIGHT: - //Clock-wise from bottom left - mux_polygon.push_back({origin.x - width / 2, origin.y - height / 2}); - mux_polygon.push_back({origin.x - width / 2, origin.y + height / 2}); - mux_polygon.push_back({origin.x + width / 2, origin.y + (scale * height) / 2}); - mux_polygon.push_back({origin.x + width / 2, origin.y - (scale * height) / 2}); - break; - - default: - VTR_ASSERT_MSG(false, "Unrecognized orientation"); - } - g->fill_poly(mux_polygon); - - ezgl::point2d min((float)mux_polygon[0].x, (float)mux_polygon[0].y); - ezgl::point2d max((float)mux_polygon[0].x, (float)mux_polygon[0].y); - for (const auto& point : mux_polygon) { - min.x = std::min((float)min.x, (float)point.x); - min.y = std::min((float)min.y, (float)point.y); - max.x = std::max((float)max.x, (float)point.x); - max.y = std::max((float)max.y, (float)point.y); - } - - return ezgl::rectangle(min, max); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, + float height, float width, float scale, ezgl::renderer *g) { + std::vector mux_polygon; + + switch (orientation) { + case TOP: + //Clock-wise from bottom left + mux_polygon.push_back( { origin.x - height / 2, origin.y - width / 2 }); + mux_polygon.push_back( + { origin.x - (scale * height) / 2, origin.y + width / 2 }); + mux_polygon.push_back( + { origin.x + (scale * height) / 2, origin.y + width / 2 }); + mux_polygon.push_back( { origin.x + height / 2, origin.y - width / 2 }); + break; + case BOTTOM: + //Clock-wise from bottom left + mux_polygon.push_back( + { origin.x - (scale * height) / 2, origin.y - width / 2 }); + mux_polygon.push_back( { origin.x - height / 2, origin.y + width / 2 }); + mux_polygon.push_back( { origin.x + height / 2, origin.y + width / 2 }); + mux_polygon.push_back( + { origin.x + (scale * height) / 2, origin.y - width / 2 }); + break; + case LEFT: + //Clock-wise from bottom left + mux_polygon.push_back( + { origin.x - width / 2, origin.y - (scale * height) / 2 }); + mux_polygon.push_back( + { origin.x - width / 2, origin.y + (scale * height) / 2 }); + mux_polygon.push_back( { origin.x + width / 2, origin.y + height / 2 }); + mux_polygon.push_back( { origin.x + width / 2, origin.y - height / 2 }); + break; + case RIGHT: + //Clock-wise from bottom left + mux_polygon.push_back( { origin.x - width / 2, origin.y - height / 2 }); + mux_polygon.push_back( { origin.x - width / 2, origin.y + height / 2 }); + mux_polygon.push_back( + { origin.x + width / 2, origin.y + (scale * height) / 2 }); + mux_polygon.push_back( + { origin.x + width / 2, origin.y - (scale * height) / 2 }); + break; + + default: + VTR_ASSERT_MSG(false, "Unrecognized orientation"); + } + g->fill_poly(mux_polygon); + + ezgl::point2d min((float) mux_polygon[0].x, (float) mux_polygon[0].y); + ezgl::point2d max((float) mux_polygon[0].x, (float) mux_polygon[0].y); + for (const auto &point : mux_polygon) { + min.x = std::min((float) min.x, (float) point.x); + min.y = std::min((float) min.y, (float) point.y); + max.x = std::max((float) max.x, (float) point.x); + max.y = std::max((float) max.y, (float) point.y); + } + + return ezgl::rectangle(min, max); } ezgl::point2d tnode_draw_coord(tatum::NodeId node) { - auto& atom_ctx = g_vpr_ctx.atom(); + auto &atom_ctx = g_vpr_ctx.atom(); - AtomPinId pin = atom_ctx.lookup.tnode_atom_pin(node); - return atom_pin_draw_coord(pin); + AtomPinId pin = atom_ctx.lookup.tnode_atom_pin(node); + return atom_pin_draw_coord(pin); } ezgl::point2d atom_pin_draw_coord(AtomPinId pin) { - auto& atom_ctx = g_vpr_ctx.atom(); + auto &atom_ctx = g_vpr_ctx.atom(); - AtomBlockId blk = atom_ctx.nlist.pin_block(pin); - ClusterBlockId clb_index = atom_ctx.lookup.atom_clb(blk); - const t_pb_graph_node* pg_gnode = atom_ctx.lookup.atom_pb_graph_node(blk); + AtomBlockId blk = atom_ctx.nlist.pin_block(pin); + ClusterBlockId clb_index = atom_ctx.lookup.atom_clb(blk); + const t_pb_graph_node *pg_gnode = atom_ctx.lookup.atom_pb_graph_node(blk); - t_draw_coords* draw_coords = get_draw_coords_vars(); - ezgl::rectangle pb_bbox = draw_coords->get_absolute_pb_bbox(clb_index, pg_gnode); + t_draw_coords *draw_coords = get_draw_coords_vars(); + ezgl::rectangle pb_bbox = draw_coords->get_absolute_pb_bbox(clb_index, + pg_gnode); - //We place each atom pin inside it's pb bounding box - //and distribute the pins along it's vertical centre line - const float FRACTION_USABLE_WIDTH = 0.8; - float width = pb_bbox.width(); - float usable_width = width * FRACTION_USABLE_WIDTH; - float x_offset = pb_bbox.left() + width * (1 - FRACTION_USABLE_WIDTH) / 2; + //We place each atom pin inside it's pb bounding box + //and distribute the pins along it's vertical centre line + const float FRACTION_USABLE_WIDTH = 0.8; + float width = pb_bbox.width(); + float usable_width = width * FRACTION_USABLE_WIDTH; + float x_offset = pb_bbox.left() + width * (1 - FRACTION_USABLE_WIDTH) / 2; - int pin_index, pin_total; - find_pin_index_at_model_scope(pin, blk, &pin_index, &pin_total); + int pin_index, pin_total; + find_pin_index_at_model_scope(pin, blk, &pin_index, &pin_total); - const ezgl::point2d point = { - x_offset + usable_width * pin_index / ((float)pin_total), - pb_bbox.center_y()}; + const ezgl::point2d point = + { x_offset + usable_width * pin_index / ((float) pin_total), + pb_bbox.center_y() }; - return point; + return point; } -static void draw_crit_path(ezgl::renderer* g) { - tatum::TimingPathCollector path_collector; - - t_draw_state* draw_state = get_draw_state_vars(); - auto& timing_ctx = g_vpr_ctx.timing(); - - if (draw_state->show_crit_path == DRAW_NO_CRIT_PATH) { - return; - } - - if (!draw_state->setup_timing_info) { - return; //No timing to draw - } - - //Get the worst timing path - auto paths = path_collector.collect_worst_setup_timing_paths(*timing_ctx.graph, *(draw_state->setup_timing_info->setup_analyzer()), 1); - tatum::TimingPath path = paths[0]; - - //Walk through the timing path drawing each edge - tatum::NodeId prev_node; - float prev_arr_time = std::numeric_limits::quiet_NaN(); - int i = 0; - for (tatum::TimingPathElem elem : path.data_arrival_path().elements()) { - tatum::NodeId node = elem.node(); - float arr_time = elem.tag().time(); - if (prev_node) { - //We draw each 'edge' in a different color, this allows users to identify the stages and - //any routing which corresponds to the edge - // - //We pick colors from the kelly max-contrast list, for long paths there may be repeats - ezgl::color color = kelly_max_contrast_colors[i++ % kelly_max_contrast_colors.size()]; - - float delay = arr_time - prev_arr_time; - if (draw_state->show_crit_path == DRAW_CRIT_PATH_FLYLINES || draw_state->show_crit_path == DRAW_CRIT_PATH_FLYLINES_DELAYS) { - g->set_color(color); - g->set_line_dash(ezgl::line_dash::none); - g->set_line_width(4); - draw_flyline_timing_edge(tnode_draw_coord(prev_node), tnode_draw_coord(node), delay, g); - } else { - VTR_ASSERT(draw_state->show_crit_path != DRAW_NO_CRIT_PATH); - - //Draw the routed version of the timing edge - draw_routed_timing_edge(prev_node, node, delay, color, g); - } - } - prev_node = node; - prev_arr_time = arr_time; - } +static void draw_crit_path(ezgl::renderer *g) { + tatum::TimingPathCollector path_collector; + + t_draw_state *draw_state = get_draw_state_vars(); + auto &timing_ctx = g_vpr_ctx.timing(); + + if (draw_state->show_crit_path == DRAW_NO_CRIT_PATH) { + return; + } + + if (!draw_state->setup_timing_info) { + return; //No timing to draw + } + + //Get the worst timing path + auto paths = path_collector.collect_worst_setup_timing_paths( + *timing_ctx.graph, + *(draw_state->setup_timing_info->setup_analyzer()), 1); + tatum::TimingPath path = paths[0]; + + //Walk through the timing path drawing each edge + tatum::NodeId prev_node; + float prev_arr_time = std::numeric_limits::quiet_NaN(); + int i = 0; + for (tatum::TimingPathElem elem : path.data_arrival_path().elements()) { + tatum::NodeId node = elem.node(); + float arr_time = elem.tag().time(); + if (prev_node) { + //We draw each 'edge' in a different color, this allows users to identify the stages and + //any routing which corresponds to the edge + // + //We pick colors from the kelly max-contrast list, for long paths there may be repeats + ezgl::color color = kelly_max_contrast_colors[i++ + % kelly_max_contrast_colors.size()]; + + float delay = arr_time - prev_arr_time; + if (draw_state->show_crit_path == DRAW_CRIT_PATH_FLYLINES + || draw_state->show_crit_path + == DRAW_CRIT_PATH_FLYLINES_DELAYS) { + g->set_color(color); + g->set_line_dash(ezgl::line_dash::none); + g->set_line_width(4); + draw_flyline_timing_edge(tnode_draw_coord(prev_node), + tnode_draw_coord(node), delay, g); + } else { + VTR_ASSERT(draw_state->show_crit_path != DRAW_NO_CRIT_PATH); + + //Draw the routed version of the timing edge + draw_routed_timing_edge(prev_node, node, delay, color, g); + } + } + prev_node = node; + prev_arr_time = arr_time; + } } -static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, float incr_delay, ezgl::renderer* g) { - g->draw_line(start, end); - draw_triangle_along_line(g, start, end, 0.95, 40 * DEFAULT_ARROW_SIZE); - draw_triangle_along_line(g, start, end, 0.05, 40 * DEFAULT_ARROW_SIZE); - - bool draw_delays = (get_draw_state_vars()->show_crit_path == DRAW_CRIT_PATH_FLYLINES_DELAYS - || get_draw_state_vars()->show_crit_path == DRAW_CRIT_PATH_ROUTING_DELAYS); - if (draw_delays) { - //Determine the strict bounding box based on the lines start/end - float min_x = std::min(start.x, end.x); - float max_x = std::max(start.x, end.x); - float min_y = std::min(start.y, end.y); - float max_y = std::max(start.y, end.y); - - //If we have a nearly horizontal/vertical line the bbox is too - //small to draw the text, so widen it by a tile (i.e. CLB) width - float tile_width = get_draw_coords_vars()->get_tile_width(); - if (max_x - min_x < tile_width) { - max_x += tile_width / 2; - min_x -= tile_width / 2; - } - if (max_y - min_y < tile_width) { - max_y += tile_width / 2; - min_y -= tile_width / 2; - } - - //TODO: draw the delays nicer - // * rotate to match edge - // * offset from line - // * track visible in window - ezgl::rectangle text_bbox({min_x, min_y}, {max_x, max_y}); - - std::stringstream ss; - ss.precision(3); - ss << 1e9 * incr_delay; //In nanoseconds - std::string incr_delay_str = ss.str(); - - // Get the angle of line, to rotate the text - float text_angle = (180 / M_PI) * atan((end.y - start.y) / (end.x - start.x)); - - // Get the screen coordinates for text drawing - ezgl::rectangle screen_coords = g->world_to_screen(text_bbox); - g->set_text_rotation(text_angle); - - // Set the text colour to black to differentiate it from the line - g->set_font_size(16); - g->set_color(ezgl::color(0, 0, 0)); - - g->set_coordinate_system(ezgl::SCREEN); - - // Find an offset so it is sitting on top/below of the line - float x_offset = screen_coords.center().x - 8 * sin(text_angle * (M_PI / 180)); - float y_offset = screen_coords.center().y - 8 * cos(text_angle * (M_PI / 180)); - - ezgl::point2d offset_text_bbox(x_offset, y_offset); - g->draw_text(offset_text_bbox, incr_delay_str.c_str(), text_bbox.width(), text_bbox.height()); - - g->set_font_size(14); - - g->set_text_rotation(0); - g->set_coordinate_system(ezgl::WORLD); - } +static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, + float incr_delay, ezgl::renderer *g) { + g->draw_line(start, end); + draw_triangle_along_line(g, start, end, 0.95, 40 * DEFAULT_ARROW_SIZE); + draw_triangle_along_line(g, start, end, 0.05, 40 * DEFAULT_ARROW_SIZE); + + bool draw_delays = (get_draw_state_vars()->show_crit_path + == DRAW_CRIT_PATH_FLYLINES_DELAYS + || get_draw_state_vars()->show_crit_path + == DRAW_CRIT_PATH_ROUTING_DELAYS); + if (draw_delays) { + //Determine the strict bounding box based on the lines start/end + float min_x = std::min(start.x, end.x); + float max_x = std::max(start.x, end.x); + float min_y = std::min(start.y, end.y); + float max_y = std::max(start.y, end.y); + + //If we have a nearly horizontal/vertical line the bbox is too + //small to draw the text, so widen it by a tile (i.e. CLB) width + float tile_width = get_draw_coords_vars()->get_tile_width(); + if (max_x - min_x < tile_width) { + max_x += tile_width / 2; + min_x -= tile_width / 2; + } + if (max_y - min_y < tile_width) { + max_y += tile_width / 2; + min_y -= tile_width / 2; + } + + //TODO: draw the delays nicer + // * rotate to match edge + // * offset from line + // * track visible in window + ezgl::rectangle text_bbox( { min_x, min_y }, { max_x, max_y }); + + std::stringstream ss; + ss.precision(3); + ss << 1e9 * incr_delay; //In nanoseconds + std::string incr_delay_str = ss.str(); + + // Get the angle of line, to rotate the text + float text_angle = (180 / M_PI) + * atan((end.y - start.y) / (end.x - start.x)); + + // Get the screen coordinates for text drawing + ezgl::rectangle screen_coords = g->world_to_screen(text_bbox); + g->set_text_rotation(text_angle); + + // Set the text colour to black to differentiate it from the line + g->set_font_size(16); + g->set_color(ezgl::color(0, 0, 0)); + + g->set_coordinate_system(ezgl::SCREEN); + + // Find an offset so it is sitting on top/below of the line + float x_offset = screen_coords.center().x + - 8 * sin(text_angle * (M_PI / 180)); + float y_offset = screen_coords.center().y + - 8 * cos(text_angle * (M_PI / 180)); + + ezgl::point2d offset_text_bbox(x_offset, y_offset); + g->draw_text(offset_text_bbox, incr_delay_str.c_str(), + text_bbox.width(), text_bbox.height()); + + g->set_font_size(14); + + g->set_text_rotation(0); + g->set_coordinate_system(ezgl::WORLD); + } } -static void draw_routed_timing_edge(tatum::NodeId start_tnode, tatum::NodeId end_tnode, float incr_delay, ezgl::color color, ezgl::renderer* g) { - draw_routed_timing_edge_connection(start_tnode, end_tnode, color, g); +static void draw_routed_timing_edge(tatum::NodeId start_tnode, + tatum::NodeId end_tnode, float incr_delay, ezgl::color color, + ezgl::renderer *g) { + draw_routed_timing_edge_connection(start_tnode, end_tnode, color, g); - g->set_line_dash(ezgl::line_dash::asymmetric_5_3); - g->set_line_width(3); - g->set_color(color); + g->set_line_dash(ezgl::line_dash::asymmetric_5_3); + g->set_line_width(3); + g->set_color(color); - draw_flyline_timing_edge((ezgl::point2d)tnode_draw_coord(start_tnode), (ezgl::point2d)tnode_draw_coord(end_tnode), (float)incr_delay, (ezgl::renderer*)g); + draw_flyline_timing_edge((ezgl::point2d) tnode_draw_coord(start_tnode), + (ezgl::point2d) tnode_draw_coord(end_tnode), (float) incr_delay, + (ezgl::renderer*) g); - g->set_line_width(0); - g->set_line_dash(ezgl::line_dash::none); + g->set_line_width(0); + g->set_line_dash(ezgl::line_dash::none); } //Collect all the drawing locations associated with the timing edge between start and end -static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, tatum::NodeId sink_tnode, ezgl::color color, ezgl::renderer* g) { - auto& atom_ctx = g_vpr_ctx.atom(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& timing_ctx = g_vpr_ctx.timing(); - - AtomPinId atom_src_pin = atom_ctx.lookup.tnode_atom_pin(src_tnode); - AtomPinId atom_sink_pin = atom_ctx.lookup.tnode_atom_pin(sink_tnode); - - std::vector points; - points.push_back(atom_pin_draw_coord(atom_src_pin)); - - tatum::EdgeId tedge = timing_ctx.graph->find_edge(src_tnode, sink_tnode); - tatum::EdgeType edge_type = timing_ctx.graph->edge_type(tedge); - - ClusterNetId net_id = ClusterNetId::INVALID(); - - //We currently only trace interconnect edges in detail, and treat all others - //as flylines - if (edge_type == tatum::EdgeType::INTERCONNECT) { - //All atom pins are implemented inside CLBs, so next hop is to the top-level CLB pins - - //TODO: most of this code is highly similar to code in PostClusterDelayCalculator, refactor - // into a common method for walking the clustered netlist, this would also (potentially) - // allow us to grab the component delays - AtomBlockId atom_src_block = atom_ctx.nlist.pin_block(atom_src_pin); - AtomBlockId atom_sink_block = atom_ctx.nlist.pin_block(atom_sink_pin); - - ClusterBlockId clb_src_block = atom_ctx.lookup.atom_clb(atom_src_block); - VTR_ASSERT(clb_src_block != ClusterBlockId::INVALID()); - ClusterBlockId clb_sink_block = atom_ctx.lookup.atom_clb(atom_sink_block); - VTR_ASSERT(clb_sink_block != ClusterBlockId::INVALID()); - - const t_pb_graph_pin* sink_gpin = atom_ctx.lookup.atom_pin_pb_graph_pin(atom_sink_pin); - VTR_ASSERT(sink_gpin); - - int sink_pb_route_id = sink_gpin->pin_count_in_cluster; - - int sink_block_pin_index = -1; - int sink_net_pin_index = -1; - - std::tie(net_id, sink_block_pin_index, sink_net_pin_index) = find_pb_route_clb_input_net_pin(clb_sink_block, sink_pb_route_id); - if (net_id != ClusterNetId::INVALID() && sink_block_pin_index != -1 && sink_net_pin_index != -1) { - //Connection leaves the CLB - //Now that we have the CLB source and sink pins, we need to grab all the points on the routing connecting the pins - VTR_ASSERT(cluster_ctx.clb_nlist.net_driver_block(net_id) == clb_src_block); - - std::vector routed_rr_nodes = trace_routed_connection_rr_nodes(net_id, 0, sink_net_pin_index); - - //Mark all the nodes highlighted - t_draw_state* draw_state = get_draw_state_vars(); - for (int inode : routed_rr_nodes) { - draw_state->draw_rr_node[inode].color = color; - } - - draw_partial_route((std::vector)routed_rr_nodes, (ezgl::renderer*)g); - } else { - //Connection entirely within the CLB, we don't draw the internal routing so treat it as a fly-line - VTR_ASSERT(clb_src_block == clb_sink_block); - } - } - - points.push_back(atom_pin_draw_coord(atom_sink_pin)); +static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, + tatum::NodeId sink_tnode, ezgl::color color, ezgl::renderer *g) { + auto &atom_ctx = g_vpr_ctx.atom(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &timing_ctx = g_vpr_ctx.timing(); + + AtomPinId atom_src_pin = atom_ctx.lookup.tnode_atom_pin(src_tnode); + AtomPinId atom_sink_pin = atom_ctx.lookup.tnode_atom_pin(sink_tnode); + + std::vector points; + points.push_back(atom_pin_draw_coord(atom_src_pin)); + + tatum::EdgeId tedge = timing_ctx.graph->find_edge(src_tnode, sink_tnode); + tatum::EdgeType edge_type = timing_ctx.graph->edge_type(tedge); + + ClusterNetId net_id = ClusterNetId::INVALID(); + + //We currently only trace interconnect edges in detail, and treat all others + //as flylines + if (edge_type == tatum::EdgeType::INTERCONNECT) { + //All atom pins are implemented inside CLBs, so next hop is to the top-level CLB pins + + //TODO: most of this code is highly similar to code in PostClusterDelayCalculator, refactor + // into a common method for walking the clustered netlist, this would also (potentially) + // allow us to grab the component delays + AtomBlockId atom_src_block = atom_ctx.nlist.pin_block(atom_src_pin); + AtomBlockId atom_sink_block = atom_ctx.nlist.pin_block(atom_sink_pin); + + ClusterBlockId clb_src_block = atom_ctx.lookup.atom_clb(atom_src_block); + VTR_ASSERT(clb_src_block != ClusterBlockId::INVALID()); + ClusterBlockId clb_sink_block = atom_ctx.lookup.atom_clb( + atom_sink_block); + VTR_ASSERT(clb_sink_block != ClusterBlockId::INVALID()); + + const t_pb_graph_pin *sink_gpin = atom_ctx.lookup.atom_pin_pb_graph_pin( + atom_sink_pin); + VTR_ASSERT(sink_gpin); + + int sink_pb_route_id = sink_gpin->pin_count_in_cluster; + + int sink_block_pin_index = -1; + int sink_net_pin_index = -1; + + std::tie(net_id, sink_block_pin_index, sink_net_pin_index) = + find_pb_route_clb_input_net_pin(clb_sink_block, + sink_pb_route_id); + if (net_id != ClusterNetId::INVALID() && sink_block_pin_index != -1 + && sink_net_pin_index != -1) { + //Connection leaves the CLB + //Now that we have the CLB source and sink pins, we need to grab all the points on the routing connecting the pins + VTR_ASSERT( + cluster_ctx.clb_nlist.net_driver_block(net_id) + == clb_src_block); + + std::vector routed_rr_nodes = trace_routed_connection_rr_nodes( + net_id, 0, sink_net_pin_index); + + //Mark all the nodes highlighted + t_draw_state *draw_state = get_draw_state_vars(); + for (int inode : routed_rr_nodes) { + draw_state->draw_rr_node[inode].color = color; + } + + draw_partial_route((std::vector) routed_rr_nodes, + (ezgl::renderer*) g); + } else { + //Connection entirely within the CLB, we don't draw the internal routing so treat it as a fly-line + VTR_ASSERT(clb_src_block == clb_sink_block); + } + } + + points.push_back(atom_pin_draw_coord(atom_sink_pin)); } //Returns the set of rr nodes which connect driver to sink -static std::vector trace_routed_connection_rr_nodes(const ClusterNetId net_id, const int driver_pin, const int sink_pin) { - auto& route_ctx = g_vpr_ctx.routing(); +static std::vector trace_routed_connection_rr_nodes( + const ClusterNetId net_id, const int driver_pin, const int sink_pin) { + auto &route_ctx = g_vpr_ctx.routing(); - bool allocated_route_tree_structs = alloc_route_tree_timing_structs(true); //Needed for traceback_to_route_tree + bool allocated_route_tree_structs = alloc_route_tree_timing_structs(true); //Needed for traceback_to_route_tree - //Conver the traceback into an easily search-able - t_rt_node* rt_root = traceback_to_route_tree(net_id); + //Conver the traceback into an easily search-able + t_rt_node *rt_root = traceback_to_route_tree(net_id); - VTR_ASSERT(rt_root && rt_root->inode == route_ctx.net_rr_terminals[net_id][driver_pin]); + VTR_ASSERT( + rt_root + && rt_root->inode + == route_ctx.net_rr_terminals[net_id][driver_pin]); - int sink_rr_node = route_ctx.net_rr_terminals[net_id][sink_pin]; + int sink_rr_node = route_ctx.net_rr_terminals[net_id][sink_pin]; - std::vector rr_nodes_on_path; + std::vector rr_nodes_on_path; - //Collect the rr nodes - trace_routed_connection_rr_nodes_recurr(rt_root, sink_rr_node, rr_nodes_on_path); + //Collect the rr nodes + trace_routed_connection_rr_nodes_recurr(rt_root, sink_rr_node, + rr_nodes_on_path); - //Traced from sink to source, but we want to draw from source to sink - std::reverse(rr_nodes_on_path.begin(), rr_nodes_on_path.end()); + //Traced from sink to source, but we want to draw from source to sink + std::reverse(rr_nodes_on_path.begin(), rr_nodes_on_path.end()); - free_route_tree(rt_root); + free_route_tree(rt_root); - if (allocated_route_tree_structs) { - free_route_tree_timing_structs(); - } - return rr_nodes_on_path; + if (allocated_route_tree_structs) { + free_route_tree_timing_structs(); + } + return rr_nodes_on_path; } //Helper function for trace_routed_connection_rr_nodes //Adds the rr nodes linking rt_node to sink_rr_node to rr_nodes_on_path //Returns true if rt_node is on the path -bool trace_routed_connection_rr_nodes_recurr(const t_rt_node* rt_node, int sink_rr_node, std::vector& rr_nodes_on_path) { - //DFS from the current rt_node to the sink_rr_node, when the sink is found trace back the used rr nodes - - if (rt_node->inode == sink_rr_node) { - rr_nodes_on_path.push_back(sink_rr_node); - return true; - } - - for (t_linked_rt_edge* edge = rt_node->u.child_list; edge != nullptr; edge = edge->next) { - t_rt_node* child_rt_node = edge->child; - VTR_ASSERT(child_rt_node); - - bool on_path_to_sink = trace_routed_connection_rr_nodes_recurr(child_rt_node, sink_rr_node, rr_nodes_on_path); - - if (on_path_to_sink) { - rr_nodes_on_path.push_back(rt_node->inode); - return true; - } - } - - return false; //Not on path to sink +bool trace_routed_connection_rr_nodes_recurr(const t_rt_node *rt_node, + int sink_rr_node, std::vector &rr_nodes_on_path) { + //DFS from the current rt_node to the sink_rr_node, when the sink is found trace back the used rr nodes + + if (rt_node->inode == sink_rr_node) { + rr_nodes_on_path.push_back(sink_rr_node); + return true; + } + + for (t_linked_rt_edge *edge = rt_node->u.child_list; edge != nullptr; edge = + edge->next) { + t_rt_node *child_rt_node = edge->child; + VTR_ASSERT(child_rt_node); + + bool on_path_to_sink = trace_routed_connection_rr_nodes_recurr( + child_rt_node, sink_rr_node, rr_nodes_on_path); + + if (on_path_to_sink) { + rr_nodes_on_path.push_back(rt_node->inode); + return true; + } + } + + return false; //Not on path to sink } //Find the edge between two rr nodes static t_edge_size find_edge(int prev_inode, int inode) { - auto& device_ctx = g_vpr_ctx.device(); - for (t_edge_size iedge = 0; iedge < device_ctx.rr_nodes[prev_inode].num_edges(); ++iedge) { - if (device_ctx.rr_nodes[prev_inode].edge_sink_node(iedge) == inode) { - return iedge; - } - } - VTR_ASSERT(false); - return OPEN; + auto &device_ctx = g_vpr_ctx.device(); + for (t_edge_size iedge = 0; + iedge < device_ctx.rr_nodes[prev_inode].num_edges(); ++iedge) { + if (device_ctx.rr_nodes[prev_inode].edge_sink_node(iedge) == inode) { + return iedge; + } + } + VTR_ASSERT(false); + return OPEN; } ezgl::color to_ezgl_color(vtr::Color color) { - return ezgl::color(color.r * 255, color.g * 255, color.b * 255); + return ezgl::color(color.r * 255, color.g * 255, color.b * 255); } -static void draw_color_map_legend(const vtr::ColorMap& cmap, ezgl::renderer* g) { - constexpr float LEGEND_WIDTH_FAC = 0.075; - constexpr float LEGEND_VERT_OFFSET_FAC = 0.05; - constexpr float TEXT_OFFSET = 10; - constexpr size_t NUM_COLOR_POINTS = 1000; - - g->set_coordinate_system(ezgl::SCREEN); - - float screen_width = application.get_canvas(application.get_main_canvas_id())->width(); - float screen_height = application.get_canvas(application.get_main_canvas_id())->height(); - float vert_offset = screen_height * LEGEND_VERT_OFFSET_FAC; - float legend_width = std::min(LEGEND_WIDTH_FAC * screen_width, 100); - - // In SCREEN coordinate: bottom_left is (0,0), right_top is (screen_width, screen_height) - ezgl::rectangle legend({0, vert_offset}, {legend_width, screen_height - vert_offset}); - - float range = cmap.max() - cmap.min(); - float height_incr = legend.height() / float(NUM_COLOR_POINTS); - for (size_t i = 0; i < NUM_COLOR_POINTS; ++i) { - float val = cmap.min() + (float(i) / NUM_COLOR_POINTS) * range; - ezgl::color color = to_ezgl_color(cmap.color(val)); - - g->set_color(color); - g->fill_rectangle({legend.left(), legend.top() - i * height_incr}, - {legend.right(), legend.top() - (i + 1) * height_incr}); - } - - //Min mark - g->set_color(blk_SKYBLUE); // set to skyblue so its easier to see - std::string str = vtr::string_fmt("%.3g", cmap.min()); - g->draw_text({legend.center_x(), legend.top() - TEXT_OFFSET}, str.c_str()); - - //Mid marker - g->set_color(ezgl::BLACK); - str = vtr::string_fmt("%.3g", cmap.min() + (cmap.range() / 2.)); - g->draw_text({legend.center_x(), legend.center_y()}, str.c_str()); - - //Max marker - g->set_color(ezgl::BLACK); - str = vtr::string_fmt("%.3g", cmap.max()); - g->draw_text({legend.center_x(), legend.bottom() + TEXT_OFFSET}, str.c_str()); - - g->set_color(ezgl::BLACK); - g->draw_rectangle(legend); - - g->set_coordinate_system(ezgl::WORLD); +static void draw_color_map_legend(const vtr::ColorMap &cmap, + ezgl::renderer *g) { + constexpr float LEGEND_WIDTH_FAC = 0.075; + constexpr float LEGEND_VERT_OFFSET_FAC = 0.05; + constexpr float TEXT_OFFSET = 10; + constexpr size_t NUM_COLOR_POINTS = 1000; + + g->set_coordinate_system(ezgl::SCREEN); + + float screen_width = application.get_canvas( + application.get_main_canvas_id())->width(); + float screen_height = application.get_canvas( + application.get_main_canvas_id())->height(); + float vert_offset = screen_height * LEGEND_VERT_OFFSET_FAC; + float legend_width = std::min(LEGEND_WIDTH_FAC * screen_width, 100); + + // In SCREEN coordinate: bottom_left is (0,0), right_top is (screen_width, screen_height) + ezgl::rectangle legend( { 0, vert_offset }, + { legend_width, screen_height - vert_offset }); + + float range = cmap.max() - cmap.min(); + float height_incr = legend.height() / float(NUM_COLOR_POINTS); + for (size_t i = 0; i < NUM_COLOR_POINTS; ++i) { + float val = cmap.min() + (float(i) / NUM_COLOR_POINTS) * range; + ezgl::color color = to_ezgl_color(cmap.color(val)); + + g->set_color(color); + g->fill_rectangle( { legend.left(), legend.top() - i * height_incr }, { + legend.right(), legend.top() - (i + 1) * height_incr }); + } + + //Min mark + g->set_color(blk_SKYBLUE); // set to skyblue so its easier to see + std::string str = vtr::string_fmt("%.3g", cmap.min()); + g->draw_text( { legend.center_x(), legend.top() - TEXT_OFFSET }, + str.c_str()); + + //Mid marker + g->set_color(ezgl::BLACK); + str = vtr::string_fmt("%.3g", cmap.min() + (cmap.range() / 2.)); + g->draw_text( { legend.center_x(), legend.center_y() }, str.c_str()); + + //Max marker + g->set_color(ezgl::BLACK); + str = vtr::string_fmt("%.3g", cmap.max()); + g->draw_text( { legend.center_x(), legend.bottom() + TEXT_OFFSET }, + str.c_str()); + + g->set_color(ezgl::BLACK); + g->draw_rectangle(legend); + + g->set_coordinate_system(ezgl::WORLD); } ezgl::color get_block_type_color(t_physical_tile_type_ptr type) { - //Wrap around if there are too many blocks - // This ensures we support an arbitrary number of types, - // although the colours may repeat - ezgl::color color = block_colors[type->index % block_colors.size()]; + //Wrap around if there are too many blocks + // This ensures we support an arbitrary number of types, + // although the colours may repeat + ezgl::color color = block_colors[type->index % block_colors.size()]; - return color; + return color; } //Lightens a color's luminance [0, 1] by an aboslute 'amount' ezgl::color lighten_color(ezgl::color color, float amount) { - constexpr double MAX_LUMINANCE = 0.95; //Clip luminance so it doesn't go full white - auto hsl = color2hsl(color); + constexpr double MAX_LUMINANCE = 0.95; //Clip luminance so it doesn't go full white + auto hsl = color2hsl(color); - hsl.l = std::max(0., std::min(MAX_LUMINANCE, hsl.l + amount)); + hsl.l = std::max(0., std::min(MAX_LUMINANCE, hsl.l + amount)); - return hsl2color(hsl); + return hsl2color(hsl); } static void draw_block_pin_util() { - t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->show_blk_pin_util == DRAW_NO_BLOCK_PIN_UTIL) return; - - auto& device_ctx = g_vpr_ctx.device(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - - std::map total_input_pins; - std::map total_output_pins; - for (const auto& type : device_ctx.physical_tile_types) { - if (is_empty_type(&type)) { - continue; - } - - total_input_pins[&type] = type.num_input_pins + type.num_clock_pins; - total_output_pins[&type] = type.num_output_pins; - } - - auto blks = cluster_ctx.clb_nlist.blocks(); - vtr::vector pin_util(blks.size()); - for (auto blk : blks) { - auto type = physical_tile_type(blk); - - if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { - pin_util[blk] = cluster_ctx.clb_nlist.block_pins(blk).size() / float(total_input_pins[type] + total_output_pins[type]); - } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_INPUTS) { - pin_util[blk] = (cluster_ctx.clb_nlist.block_input_pins(blk).size() + cluster_ctx.clb_nlist.block_clock_pins(blk).size()) / float(total_input_pins[type]); - } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { - pin_util[blk] = (cluster_ctx.clb_nlist.block_output_pins(blk).size()) / float(total_output_pins[type]); - } else { - VTR_ASSERT(false); - } - } - - std::unique_ptr cmap = std::make_unique(0., 1.); - - for (auto blk : blks) { - ezgl::color color = to_ezgl_color(cmap->color(pin_util[blk])); - draw_state->set_block_color(blk, color); - } - - draw_state->color_map = std::move(cmap); - - if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { - application.update_message("Block Total Pin Utilization"); - } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_INPUTS) { - application.update_message("Block Input Pin Utilization"); - - } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { - application.update_message("Block Output Pin Utilization"); - } else { - VTR_ASSERT(false); - } + t_draw_state *draw_state = get_draw_state_vars(); + if (draw_state->show_blk_pin_util == DRAW_NO_BLOCK_PIN_UTIL) + return; + + auto &device_ctx = g_vpr_ctx.device(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + + std::map total_input_pins; + std::map total_output_pins; + for (const auto &type : device_ctx.physical_tile_types) { + if (is_empty_type(&type)) { + continue; + } + + total_input_pins[&type] = type.num_input_pins + type.num_clock_pins; + total_output_pins[&type] = type.num_output_pins; + } + + auto blks = cluster_ctx.clb_nlist.blocks(); + vtr::vector pin_util(blks.size()); + for (auto blk : blks) { + auto type = physical_tile_type(blk); + + if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { + pin_util[blk] = cluster_ctx.clb_nlist.block_pins(blk).size() + / float(total_input_pins[type] + total_output_pins[type]); + } else if (draw_state->show_blk_pin_util + == DRAW_BLOCK_PIN_UTIL_INPUTS) { + pin_util[blk] = (cluster_ctx.clb_nlist.block_input_pins(blk).size() + + cluster_ctx.clb_nlist.block_clock_pins(blk).size()) + / float(total_input_pins[type]); + } else if (draw_state->show_blk_pin_util + == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { + pin_util[blk] = + (cluster_ctx.clb_nlist.block_output_pins(blk).size()) + / float(total_output_pins[type]); + } else { + VTR_ASSERT(false); + } + } + + std::unique_ptr cmap = std::make_unique( + 0., 1.); + + for (auto blk : blks) { + ezgl::color color = to_ezgl_color(cmap->color(pin_util[blk])); + draw_state->set_block_color(blk, color); + } + + draw_state->color_map = std::move(cmap); + + if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { + application.update_message("Block Total Pin Utilization"); + } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_INPUTS) { + application.update_message("Block Input Pin Utilization"); + + } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { + application.update_message("Block Output Pin Utilization"); + } else { + VTR_ASSERT(false); + } } static void draw_reset_blk_colors() { - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto blks = cluster_ctx.clb_nlist.blocks(); - for (auto blk : blks) { - draw_reset_blk_color(blk); - } + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto blks = cluster_ctx.clb_nlist.blocks(); + for (auto blk : blks) { + draw_reset_blk_color(blk); + } } -static void draw_routing_util(ezgl::renderer* g) { - t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { - return; - } - - t_draw_coords* draw_coords = get_draw_coords_vars(); - auto& device_ctx = g_vpr_ctx.device(); - - auto chanx_usage = calculate_routing_usage(CHANX); - auto chany_usage = calculate_routing_usage(CHANY); - - auto chanx_avail = calculate_routing_avail(CHANX); - auto chany_avail = calculate_routing_avail(CHANY); - - float min_util = 0.; - float max_util = -std::numeric_limits::infinity(); - for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { - for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { - max_util = std::max(max_util, routing_util(chanx_usage[x][y], chanx_avail[x][y])); - max_util = std::max(max_util, routing_util(chany_usage[x][y], chany_avail[x][y])); - } - } - max_util = std::max(max_util, 1.f); - - std::unique_ptr cmap; - - if (draw_state->clip_routing_util) { - cmap = std::make_unique(0., 1.); - } else { - cmap = std::make_unique(min_util, max_util); - } - - float tile_width = draw_coords->get_tile_width(); - float tile_height = draw_coords->get_tile_height(); - - float ALPHA = 0.95; - if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_OVER_BLOCKS) { - ALPHA = 1.; - } - - for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { - for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { - float sb_util = 0; - float chanx_util = 0; - float chany_util = 0; - int chan_count = 0; - if (x > 0) { - chanx_util = routing_util(chanx_usage[x][y], chanx_avail[x][y]); - if (draw_state->clip_routing_util) { - chanx_util = std::min(chanx_util, 1.f); - } - ezgl::color chanx_color = to_ezgl_color(cmap->color(chanx_util)); - chanx_color.alpha *= ALPHA; - g->set_color(chanx_color); - ezgl::rectangle bb({draw_coords->tile_x[x], draw_coords->tile_y[y] + 1 * tile_height}, - {draw_coords->tile_x[x] + 1 * tile_width, draw_coords->tile_y[y + 1]}); - g->fill_rectangle(bb); - - g->set_color(ezgl::BLACK); - if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_VALUE) { - g->draw_text(bb.center(), vtr::string_fmt("%.2f", chanx_util).c_str(), bb.width(), bb.height()); - } else if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_FORMULA) { - g->draw_text(bb.center(), vtr::string_fmt("%.2f = %.0f / %.0f", chanx_util, chanx_usage[x][y], chanx_avail[x][y]).c_str(), bb.width(), bb.height()); - } - - sb_util += chanx_util; - ++chan_count; - } - - if (y > 0) { - chany_util = routing_util(chany_usage[x][y], chany_avail[x][y]); - if (draw_state->clip_routing_util) { - chany_util = std::min(chany_util, 1.f); - } - ezgl::color chany_color = to_ezgl_color(cmap->color(chany_util)); - chany_color.alpha *= ALPHA; - g->set_color(chany_color); - ezgl::rectangle bb({draw_coords->tile_x[x] + 1 * tile_width, draw_coords->tile_y[y]}, - {draw_coords->tile_x[x + 1], draw_coords->tile_y[y] + 1 * tile_height}); - g->fill_rectangle(bb); - - g->set_color(ezgl::BLACK); - if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_VALUE) { - g->draw_text(bb.center(), vtr::string_fmt("%.2f", chany_util).c_str(), bb.width(), bb.height()); - } else if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_FORMULA) { - g->draw_text(bb.center(), vtr::string_fmt("%.2f = %.0f / %.0f", chany_util, chany_usage[x][y], chany_avail[x][y]).c_str(), bb.width(), bb.height()); - } - - sb_util += chany_util; - ++chan_count; - } - - //For now SB util is just average of surrounding channels - //TODO: calculate actual usage - sb_util += routing_util(chanx_usage[x + 1][y], chanx_avail[x + 1][y]); - chan_count += 1; - sb_util += routing_util(chany_usage[x][y + 1], chany_avail[x][y + 1]); - chan_count += 1; - - VTR_ASSERT(chan_count > 0); - sb_util /= chan_count; - if (draw_state->clip_routing_util) { - sb_util = std::min(sb_util, 1.f); - } - ezgl::color sb_color = to_ezgl_color(cmap->color(sb_util)); - sb_color.alpha *= ALPHA; - g->set_color(sb_color); - ezgl::rectangle bb({draw_coords->tile_x[x] + 1 * tile_width, draw_coords->tile_y[y] + 1 * tile_height}, - {draw_coords->tile_x[x + 1], draw_coords->tile_y[y + 1]}); - g->fill_rectangle(bb); - - //Draw over blocks - if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_OVER_BLOCKS) { - if (x < device_ctx.grid.width() - 2 && y < device_ctx.grid.height() - 2) { - ezgl::rectangle bb2({draw_coords->tile_x[x + 1], draw_coords->tile_y[y + 1]}, - {draw_coords->tile_x[x + 1] + 1 * tile_width, draw_coords->tile_y[y + 1] + 1 * tile_width}); - g->fill_rectangle(bb2); - } - } - g->set_color(ezgl::BLACK); - if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_VALUE - || draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_FORMULA) { - g->draw_text(bb.center(), vtr::string_fmt("%.2f", sb_util).c_str(), bb.width(), bb.height()); - } - } - } - - draw_state->color_map = std::move(cmap); +static void draw_routing_util(ezgl::renderer *g) { + t_draw_state *draw_state = get_draw_state_vars(); + if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { + return; + } + + t_draw_coords *draw_coords = get_draw_coords_vars(); + auto &device_ctx = g_vpr_ctx.device(); + + auto chanx_usage = calculate_routing_usage(CHANX); + auto chany_usage = calculate_routing_usage(CHANY); + + auto chanx_avail = calculate_routing_avail(CHANX); + auto chany_avail = calculate_routing_avail(CHANY); + + float min_util = 0.; + float max_util = -std::numeric_limits::infinity(); + for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { + for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { + max_util = std::max(max_util, + routing_util(chanx_usage[x][y], chanx_avail[x][y])); + max_util = std::max(max_util, + routing_util(chany_usage[x][y], chany_avail[x][y])); + } + } + max_util = std::max(max_util, 1.f); + + std::unique_ptr cmap; + + if (draw_state->clip_routing_util) { + cmap = std::make_unique(0., 1.); + } else { + cmap = std::make_unique(min_util, max_util); + } + + float tile_width = draw_coords->get_tile_width(); + float tile_height = draw_coords->get_tile_height(); + + float ALPHA = 0.95; + if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_OVER_BLOCKS) { + ALPHA = 1.; + } + + for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { + for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { + float sb_util = 0; + float chanx_util = 0; + float chany_util = 0; + int chan_count = 0; + if (x > 0) { + chanx_util = routing_util(chanx_usage[x][y], chanx_avail[x][y]); + if (draw_state->clip_routing_util) { + chanx_util = std::min(chanx_util, 1.f); + } + ezgl::color chanx_color = to_ezgl_color( + cmap->color(chanx_util)); + chanx_color.alpha *= ALPHA; + g->set_color(chanx_color); + ezgl::rectangle bb( + { draw_coords->tile_x[x], draw_coords->tile_y[y] + + 1 * tile_height }, + { draw_coords->tile_x[x] + 1 * tile_width, + draw_coords->tile_y[y + 1] }); + g->fill_rectangle(bb); + + g->set_color(ezgl::BLACK); + if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_VALUE) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f", chanx_util).c_str(), + bb.width(), bb.height()); + } else if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_FORMULA) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f = %.0f / %.0f", chanx_util, + chanx_usage[x][y], chanx_avail[x][y]).c_str(), + bb.width(), bb.height()); + } + + sb_util += chanx_util; + ++chan_count; + } + + if (y > 0) { + chany_util = routing_util(chany_usage[x][y], chany_avail[x][y]); + if (draw_state->clip_routing_util) { + chany_util = std::min(chany_util, 1.f); + } + ezgl::color chany_color = to_ezgl_color( + cmap->color(chany_util)); + chany_color.alpha *= ALPHA; + g->set_color(chany_color); + ezgl::rectangle bb( { draw_coords->tile_x[x] + 1 * tile_width, + draw_coords->tile_y[y] }, + { draw_coords->tile_x[x + 1], draw_coords->tile_y[y] + + 1 * tile_height }); + g->fill_rectangle(bb); + + g->set_color(ezgl::BLACK); + if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_VALUE) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f", chany_util).c_str(), + bb.width(), bb.height()); + } else if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_FORMULA) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f = %.0f / %.0f", chany_util, + chany_usage[x][y], chany_avail[x][y]).c_str(), + bb.width(), bb.height()); + } + + sb_util += chany_util; + ++chan_count; + } + + //For now SB util is just average of surrounding channels + //TODO: calculate actual usage + sb_util += routing_util(chanx_usage[x + 1][y], + chanx_avail[x + 1][y]); + chan_count += 1; + sb_util += routing_util(chany_usage[x][y + 1], + chany_avail[x][y + 1]); + chan_count += 1; + + VTR_ASSERT(chan_count > 0); + sb_util /= chan_count; + if (draw_state->clip_routing_util) { + sb_util = std::min(sb_util, 1.f); + } + ezgl::color sb_color = to_ezgl_color(cmap->color(sb_util)); + sb_color.alpha *= ALPHA; + g->set_color(sb_color); + ezgl::rectangle bb( + { draw_coords->tile_x[x] + 1 * tile_width, + draw_coords->tile_y[y] + 1 * tile_height }, + { draw_coords->tile_x[x + 1], draw_coords->tile_y[y + 1] }); + g->fill_rectangle(bb); + + //Draw over blocks + if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_OVER_BLOCKS) { + if (x < device_ctx.grid.width() - 2 + && y < device_ctx.grid.height() - 2) { + ezgl::rectangle bb2( { draw_coords->tile_x[x + 1], + draw_coords->tile_y[y + 1] }, + { draw_coords->tile_x[x + 1] + 1 * tile_width, + draw_coords->tile_y[y + 1] + 1 * tile_width }); + g->fill_rectangle(bb2); + } + } + g->set_color(ezgl::BLACK); + if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_VALUE + || draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_FORMULA) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f", sb_util).c_str(), bb.width(), + bb.height()); + } + } + } + + draw_state->color_map = std::move(cmap); } -static float get_router_expansion_cost(const t_rr_node_route_inf node_inf, e_draw_router_expansion_cost draw_router_expansion_cost) { - if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL || draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { - return node_inf.path_cost; - } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN || draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { - return node_inf.backward_path_cost; - } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED || draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { - return node_inf.path_cost - node_inf.backward_path_cost; - } - - VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); +static float get_router_expansion_cost(const t_rr_node_route_inf node_inf, + e_draw_router_expansion_cost draw_router_expansion_cost) { + if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL + || draw_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { + return node_inf.path_cost; + } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN + || draw_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { + return node_inf.backward_path_cost; + } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED + || draw_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { + return node_inf.path_cost - node_inf.backward_path_cost; + } + + VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); } -static void draw_router_expansion_costs(ezgl::renderer* g) { - t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->show_router_expansion_cost == DRAW_NO_ROUTER_EXPANSION_COST) { - return; - } - - auto& device_ctx = g_vpr_ctx.device(); - auto& routing_ctx = g_vpr_ctx.routing(); - - std::vector rr_costs(device_ctx.rr_nodes.size()); - - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - float cost = get_router_expansion_cost(routing_ctx.rr_node_route_inf[inode], draw_state->show_router_expansion_cost); - rr_costs[inode] = cost; - } - - bool all_nan = true; - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - if (std::isinf(rr_costs[inode])) { - rr_costs[inode] = NAN; - } else { - all_nan = false; - } - } - - if (!all_nan) { - draw_rr_costs(g, rr_costs, false); - } - if (draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL || draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { - application.update_message("Routing Expected Total Cost (known + estimate)"); - } else if (draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN || draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { - application.update_message("Routing Known Cost (from source to node)"); - } else if (draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED || draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { - application.update_message("Routing Expected Cost (from node to target)"); - } else { - VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); - } +static void draw_router_expansion_costs(ezgl::renderer *g) { + t_draw_state *draw_state = get_draw_state_vars(); + if (draw_state->show_router_expansion_cost + == DRAW_NO_ROUTER_EXPANSION_COST) { + return; + } + + auto &device_ctx = g_vpr_ctx.device(); + auto &routing_ctx = g_vpr_ctx.routing(); + + std::vector rr_costs(device_ctx.rr_nodes.size()); + + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + float cost = get_router_expansion_cost( + routing_ctx.rr_node_route_inf[inode], + draw_state->show_router_expansion_cost); + rr_costs[inode] = cost; + } + + bool all_nan = true; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + if (std::isinf(rr_costs[inode])) { + rr_costs[inode] = NAN; + } else { + all_nan = false; + } + } + + if (!all_nan) { + draw_rr_costs(g, rr_costs, false); + } + if (draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_TOTAL + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { + application.update_message( + "Routing Expected Total Cost (known + estimate)"); + } else if (draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_KNOWN + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { + application.update_message("Routing Known Cost (from source to node)"); + } else if (draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_EXPECTED + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { + application.update_message( + "Routing Expected Cost (from node to target)"); + } else { + VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); + } } -static void draw_rr_costs(ezgl::renderer* g, const std::vector& rr_costs, bool lowest_cost_first) { - t_draw_state* draw_state = get_draw_state_vars(); - - /* Draws routing costs */ - - auto& device_ctx = g_vpr_ctx.device(); - - g->set_line_width(0); - - bool with_edges = (draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES - || draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES - || draw_state->show_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES); - - VTR_ASSERT(rr_costs.size() == device_ctx.rr_nodes.size()); - - float min_cost = std::numeric_limits::infinity(); - float max_cost = -min_cost; - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - if (std::isnan(rr_costs[inode])) continue; - - min_cost = std::min(min_cost, rr_costs[inode]); - max_cost = std::max(max_cost, rr_costs[inode]); - } - if (min_cost == std::numeric_limits::infinity()) min_cost = 0; - if (max_cost == -std::numeric_limits::infinity()) max_cost = 0; - std::unique_ptr cmap = std::make_unique(min_cost, max_cost); - - //Draw the nodes in ascending order of value, this ensures high valued nodes - //are not overdrawn by lower value ones (e.g-> when zoomed-out far) - std::vector nodes(device_ctx.rr_nodes.size()); - std::iota(nodes.begin(), nodes.end(), 0); - auto cmp_ascending_cost = [&](int lhs_node, int rhs_node) { - if (lowest_cost_first) { - return rr_costs[lhs_node] > rr_costs[rhs_node]; - } - return rr_costs[lhs_node] < rr_costs[rhs_node]; - }; - std::sort(nodes.begin(), nodes.end(), cmp_ascending_cost); - - for (int inode : nodes) { - float cost = rr_costs[inode]; - if (std::isnan(cost)) continue; - - ezgl::color color = to_ezgl_color(cmap->color(cost)); - - switch (device_ctx.rr_nodes[inode].type()) { - case CHANX: //fallthrough - case CHANY: - draw_rr_chan(inode, color, g); - if (with_edges) draw_rr_edges(inode, g); - break; - - case IPIN: //fallthrough - draw_rr_pin(inode, color, g); - if (with_edges) draw_rr_edges(inode, g); - break; - case OPIN: - draw_rr_pin(inode, color, g); - if (with_edges) draw_rr_edges(inode, g); - break; - case SOURCE: - case SINK: - color.alpha *= 0.8; - draw_rr_src_sink(inode, color, g); - if (with_edges) draw_rr_edges(inode, g); - break; - default: - break; - } - } - - draw_state->color_map = std::move(cmap); +static void draw_rr_costs(ezgl::renderer *g, const std::vector &rr_costs, + bool lowest_cost_first) { + t_draw_state *draw_state = get_draw_state_vars(); + + /* Draws routing costs */ + + auto &device_ctx = g_vpr_ctx.device(); + + g->set_line_width(0); + + bool with_edges = (draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES); + + VTR_ASSERT(rr_costs.size() == device_ctx.rr_nodes.size()); + + float min_cost = std::numeric_limits::infinity(); + float max_cost = -min_cost; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + if (std::isnan(rr_costs[inode])) + continue; + + min_cost = std::min(min_cost, rr_costs[inode]); + max_cost = std::max(max_cost, rr_costs[inode]); + } + if (min_cost == std::numeric_limits::infinity()) + min_cost = 0; + if (max_cost == -std::numeric_limits::infinity()) + max_cost = 0; + std::unique_ptr cmap = std::make_unique( + min_cost, max_cost); + + //Draw the nodes in ascending order of value, this ensures high valued nodes + //are not overdrawn by lower value ones (e.g-> when zoomed-out far) + std::vector nodes(device_ctx.rr_nodes.size()); + std::iota(nodes.begin(), nodes.end(), 0); + auto cmp_ascending_cost = [&](int lhs_node, int rhs_node) { + if (lowest_cost_first) { + return rr_costs[lhs_node] > rr_costs[rhs_node]; + } + return rr_costs[lhs_node] < rr_costs[rhs_node]; + }; + std::sort(nodes.begin(), nodes.end(), cmp_ascending_cost); + + for (int inode : nodes) { + float cost = rr_costs[inode]; + if (std::isnan(cost)) + continue; + + ezgl::color color = to_ezgl_color(cmap->color(cost)); + + switch (device_ctx.rr_nodes[inode].type()) { + case CHANX: //fallthrough + case CHANY: + draw_rr_chan(inode, color, g); + if (with_edges) + draw_rr_edges(inode, g); + break; + + case IPIN: //fallthrough + draw_rr_pin(inode, color, g); + if (with_edges) + draw_rr_edges(inode, g); + break; + case OPIN: + draw_rr_pin(inode, color, g); + if (with_edges) + draw_rr_edges(inode, g); + break; + case SOURCE: + case SINK: + color.alpha *= 0.8; + draw_rr_src_sink(inode, color, g); + if (with_edges) + draw_rr_edges(inode, g); + break; + default: + break; + } + } + + draw_state->color_map = std::move(cmap); } -static void draw_placement_macros(ezgl::renderer* g) { - t_draw_state* draw_state = get_draw_state_vars(); - - if (draw_state->show_placement_macros == DRAW_NO_PLACEMENT_MACROS) { - return; - } - t_draw_coords* draw_coords = get_draw_coords_vars(); - - auto& place_ctx = g_vpr_ctx.placement(); - for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); ++imacro) { - const t_pl_macro* pl_macro = &place_ctx.pl_macros[imacro]; - - //TODO: for now we just draw the bounding box of the macro, which is incorrect for non-rectangular macros... - int xlow = std::numeric_limits::max(); - int ylow = std::numeric_limits::max(); - int xhigh = std::numeric_limits::min(); - int yhigh = std::numeric_limits::min(); - - int x_root = OPEN; - int y_root = OPEN; - for (size_t imember = 0; imember < pl_macro->members.size(); ++imember) { - const t_pl_macro_member* member = &pl_macro->members[imember]; - - ClusterBlockId blk = member->blk_index; - - if (imember == 0) { - x_root = place_ctx.block_locs[blk].loc.x; - y_root = place_ctx.block_locs[blk].loc.y; - } - - int x = x_root + member->offset.x; - int y = y_root + member->offset.y; - - xlow = std::min(xlow, x); - ylow = std::min(ylow, y); - xhigh = std::max(xhigh, x + physical_tile_type(blk)->width); - yhigh = std::max(yhigh, y + physical_tile_type(blk)->height); - } - - double draw_xlow = draw_coords->tile_x[xlow]; - double draw_ylow = draw_coords->tile_y[ylow]; - double draw_xhigh = draw_coords->tile_x[xhigh]; - double draw_yhigh = draw_coords->tile_y[yhigh]; - - g->set_color(blk_RED); - g->draw_rectangle({draw_xlow, draw_ylow}, {draw_xhigh, draw_yhigh}); - - ezgl::color fill = blk_SKYBLUE; - fill.alpha *= 0.3; - g->set_color(fill); - g->fill_rectangle({draw_xlow, draw_ylow}, {draw_xhigh, draw_yhigh}); - } +static void draw_placement_macros(ezgl::renderer *g) { + t_draw_state *draw_state = get_draw_state_vars(); + + if (draw_state->show_placement_macros == DRAW_NO_PLACEMENT_MACROS) { + return; + } + t_draw_coords *draw_coords = get_draw_coords_vars(); + + auto &place_ctx = g_vpr_ctx.placement(); + for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); ++imacro) { + const t_pl_macro *pl_macro = &place_ctx.pl_macros[imacro]; + + //TODO: for now we just draw the bounding box of the macro, which is incorrect for non-rectangular macros... + int xlow = std::numeric_limits::max(); + int ylow = std::numeric_limits::max(); + int xhigh = std::numeric_limits::min(); + int yhigh = std::numeric_limits::min(); + + int x_root = OPEN; + int y_root = OPEN; + for (size_t imember = 0; imember < pl_macro->members.size(); + ++imember) { + const t_pl_macro_member *member = &pl_macro->members[imember]; + + ClusterBlockId blk = member->blk_index; + + if (imember == 0) { + x_root = place_ctx.block_locs[blk].loc.x; + y_root = place_ctx.block_locs[blk].loc.y; + } + + int x = x_root + member->offset.x; + int y = y_root + member->offset.y; + + xlow = std::min(xlow, x); + ylow = std::min(ylow, y); + xhigh = std::max(xhigh, x + physical_tile_type(blk)->width); + yhigh = std::max(yhigh, y + physical_tile_type(blk)->height); + } + + double draw_xlow = draw_coords->tile_x[xlow]; + double draw_ylow = draw_coords->tile_y[ylow]; + double draw_xhigh = draw_coords->tile_x[xhigh]; + double draw_yhigh = draw_coords->tile_y[yhigh]; + + g->set_color(blk_RED); + g->draw_rectangle( { draw_xlow, draw_ylow }, + { draw_xhigh, draw_yhigh }); + + ezgl::color fill = blk_SKYBLUE; + fill.alpha *= 0.3; + g->set_color(fill); + g->fill_rectangle( { draw_xlow, draw_ylow }, + { draw_xhigh, draw_yhigh }); + } } static void highlight_blocks(double x, double y) { - t_draw_coords* draw_coords = get_draw_coords_vars(); - - char msg[vtr::bufsize]; - ClusterBlockId clb_index = EMPTY_BLOCK_ID; - auto& device_ctx = g_vpr_ctx.device(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.placement(); - - /// determine block /// - ezgl::rectangle clb_bbox; - - // iterate over grid x - for (size_t i = 0; i < device_ctx.grid.width(); ++i) { - if (draw_coords->tile_x[i] > x) { - break; // we've gone to far in the x direction - } - // iterate over grid y - for (size_t j = 0; j < device_ctx.grid.height(); ++j) { - if (draw_coords->tile_y[j] > y) { - break; // we've gone to far in the y direction - } - // iterate over sub_blocks - const t_grid_tile* grid_tile = &device_ctx.grid[i][j]; - for (int k = 0; k < grid_tile->type->capacity; ++k) { - clb_index = place_ctx.grid_blocks[i][j].blocks[k]; - if (clb_index != EMPTY_BLOCK_ID) { - clb_bbox = draw_coords->get_absolute_clb_bbox(clb_index, cluster_ctx.clb_nlist.block_type(clb_index)); - if (clb_bbox.contains({x, y})) { - break; - } else { - clb_index = EMPTY_BLOCK_ID; - } - } - } - if (clb_index != EMPTY_BLOCK_ID) { - break; // we've found something - } - } - if (clb_index != EMPTY_BLOCK_ID) { - break; // we've found something - } - } - - if (clb_index == EMPTY_BLOCK_ID || clb_index == ClusterBlockId::INVALID()) { - //Nothing found - return; - } - - VTR_ASSERT(clb_index != EMPTY_BLOCK_ID); - - // note: this will clear the selected sub-block if show_blk_internal is 0, - // or if it doesn't find anything - ezgl::point2d point_in_clb = ezgl::point2d(x, y) - clb_bbox.bottom_left(); - highlight_sub_block(point_in_clb, clb_index, cluster_ctx.clb_nlist.block_pb(clb_index)); - - if (get_selected_sub_block_info().has_selection()) { - t_pb* selected_subblock = get_selected_sub_block_info().get_selected_pb(); - sprintf(msg, "sub-block %s (a \"%s\") selected", - selected_subblock->name, selected_subblock->pb_graph_node->pb_type->name); - } else { - /* Highlight block and fan-in/fan-outs. */ - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); - sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index), cluster_ctx.clb_nlist.block_name(clb_index).c_str(), place_ctx.block_locs[clb_index].loc.x, place_ctx.block_locs[clb_index].loc.y); - } - - //If manual moves is activated, then user can select block from the grid. - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - if(get_manual_move_flag()) { - if(!manual_move_global->mm_window_is_open) { - draw_manual_moves_window(std::to_string(size_t(clb_index))); - } - } - - application.update_message(msg); - application.refresh_drawing(); + t_draw_coords *draw_coords = get_draw_coords_vars(); + + char msg[vtr::bufsize]; + ClusterBlockId clb_index = EMPTY_BLOCK_ID; + auto &device_ctx = g_vpr_ctx.device(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_ctx = g_vpr_ctx.placement(); + + /// determine block /// + ezgl::rectangle clb_bbox; + + // iterate over grid x + for (size_t i = 0; i < device_ctx.grid.width(); ++i) { + if (draw_coords->tile_x[i] > x) { + break; // we've gone to far in the x direction + } + // iterate over grid y + for (size_t j = 0; j < device_ctx.grid.height(); ++j) { + if (draw_coords->tile_y[j] > y) { + break; // we've gone to far in the y direction + } + // iterate over sub_blocks + const t_grid_tile *grid_tile = &device_ctx.grid[i][j]; + for (int k = 0; k < grid_tile->type->capacity; ++k) { + clb_index = place_ctx.grid_blocks[i][j].blocks[k]; + if (clb_index != EMPTY_BLOCK_ID) { + clb_bbox = draw_coords->get_absolute_clb_bbox(clb_index, + cluster_ctx.clb_nlist.block_type(clb_index)); + if (clb_bbox.contains( { x, y })) { + break; + } else { + clb_index = EMPTY_BLOCK_ID; + } + } + } + if (clb_index != EMPTY_BLOCK_ID) { + break; // we've found something + } + } + if (clb_index != EMPTY_BLOCK_ID) { + break; // we've found something + } + } + + if (clb_index == EMPTY_BLOCK_ID || clb_index == ClusterBlockId::INVALID()) { + //Nothing found + return; + } + + VTR_ASSERT(clb_index != EMPTY_BLOCK_ID); + + // note: this will clear the selected sub-block if show_blk_internal is 0, + // or if it doesn't find anything + ezgl::point2d point_in_clb = ezgl::point2d(x, y) - clb_bbox.bottom_left(); + highlight_sub_block(point_in_clb, clb_index, + cluster_ctx.clb_nlist.block_pb(clb_index)); + + if (get_selected_sub_block_info().has_selection()) { + t_pb *selected_subblock = + get_selected_sub_block_info().get_selected_pb(); + sprintf(msg, "sub-block %s (a \"%s\") selected", + selected_subblock->name, + selected_subblock->pb_graph_node->pb_type->name); + } else { + /* Highlight block and fan-in/fan-outs. */ + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), + clb_index); + sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index), + cluster_ctx.clb_nlist.block_name(clb_index).c_str(), + place_ctx.block_locs[clb_index].loc.x, + place_ctx.block_locs[clb_index].loc.y); + } + + //If manual moves is activated, then user can select block from the grid. + ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + manual_move_global->user_highlighted_block = true; + if (get_manual_move_flag()) { + if (!manual_move_global->mm_window_is_open) { + draw_manual_moves_window(std::to_string(size_t(clb_index))); + } + } + + application.update_message(msg); + application.refresh_drawing(); } -void set_net_alpha_value(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { - std::string fa(gtk_entry_get_text((GtkEntry*)widget)); - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->net_alpha = std::stof(fa); - application.refresh_drawing(); +void set_net_alpha_value(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/) { + std::string fa(gtk_entry_get_text((GtkEntry*) widget)); + t_draw_state *draw_state = get_draw_state_vars(); + draw_state->net_alpha = std::stof(fa); + application.refresh_drawing(); } -void set_net_alpha_value_with_enter(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { - std::string fa(gtk_entry_get_text((GtkEntry*)widget)); - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->net_alpha = std::stof(fa); - application.refresh_drawing(); +void set_net_alpha_value_with_enter(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/) { + std::string fa(gtk_entry_get_text((GtkEntry*) widget)); + t_draw_state *draw_state = get_draw_state_vars(); + draw_state->net_alpha = std::stof(fa); + application.refresh_drawing(); } float get_net_alpha() { - t_draw_state* draw_state = get_draw_state_vars(); - return draw_state->net_alpha; + t_draw_state *draw_state = get_draw_state_vars(); + return draw_state->net_alpha; } -static void setup_default_ezgl_callbacks(ezgl::application* app) { - // Connect press_proceed function to the Proceed button - GObject* proceed_button = app->get_object("ProceedButton"); - g_signal_connect(proceed_button, "clicked", G_CALLBACK(ezgl::press_proceed), app); +static void setup_default_ezgl_callbacks(ezgl::application *app) { + // Connect press_proceed function to the Proceed button + GObject *proceed_button = app->get_object("ProceedButton"); + g_signal_connect(proceed_button, "clicked", G_CALLBACK(ezgl::press_proceed), + app); - // Connect press_zoom_fit function to the Zoom-fit button - GObject* zoom_fit_button = app->get_object("ZoomFitButton"); - g_signal_connect(zoom_fit_button, "clicked", G_CALLBACK(ezgl::press_zoom_fit), app); + // Connect press_zoom_fit function to the Zoom-fit button + GObject *zoom_fit_button = app->get_object("ZoomFitButton"); + g_signal_connect(zoom_fit_button, "clicked", + G_CALLBACK(ezgl::press_zoom_fit), app); - // Connect Pause button - GObject* pause_button = app->get_object("PauseButton"); - g_signal_connect(pause_button, "clicked", G_CALLBACK(set_force_pause), app); + // Connect Pause button + GObject *pause_button = app->get_object("PauseButton"); + g_signal_connect(pause_button, "clicked", G_CALLBACK(set_force_pause), app); - // Connect Block Outline checkbox - GObject* block_outline = app->get_object("blockOutline"); - g_signal_connect(block_outline, "toggled", G_CALLBACK(set_block_outline), app); + // Connect Block Outline checkbox + GObject *block_outline = app->get_object("blockOutline"); + g_signal_connect(block_outline, "toggled", G_CALLBACK(set_block_outline), + app); - // Connect Block Text checkbox - GObject* block_text = app->get_object("blockText"); - g_signal_connect(block_text, "toggled", G_CALLBACK(set_block_text), app); + // Connect Block Text checkbox + GObject *block_text = app->get_object("blockText"); + g_signal_connect(block_text, "toggled", G_CALLBACK(set_block_text), app); - // Connect Clip Routing Util checkbox - GObject* clip_routing = app->get_object("clipRoutingUtil"); - g_signal_connect(clip_routing, "toggled", G_CALLBACK(clip_routing_util), app); + // Connect Clip Routing Util checkbox + GObject *clip_routing = app->get_object("clipRoutingUtil"); + g_signal_connect(clip_routing, "toggled", G_CALLBACK(clip_routing_util), + app); - // Connect Debug Button - GObject* debugger = app->get_object("debugButton"); - g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); + // Connect Debug Button + GObject *debugger = app->get_object("debugButton"); + g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); - // Connect Manual Moves checkbox - //GObject* manual_moves = app->get_object("manualMove"); - //g_signal_connect(manual_moves, "toggled", G_CALLBACK(manual_moves_callback), app); } -//Toggle function for manual moves -//static void manual_moves_callback(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/, ezgl::application* app) { - /* if(gtk_toggle_button_get_active((GtkToggleButton*)widget)) { - //std::cout << "Checkbox was pressed" << std::endl; - //draw_manual_moves_window(""); - } -}*/ - // Callback function for Block Outline checkbox -static void set_block_outline(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { - t_draw_state* draw_state = get_draw_state_vars(); - - // assign corresponding bool value to draw_state->draw_block_outlines - if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) - draw_state->draw_block_outlines = true; - else - draw_state->draw_block_outlines = false; - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +static void set_block_outline(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/) { + t_draw_state *draw_state = get_draw_state_vars(); + + // assign corresponding bool value to draw_state->draw_block_outlines + if (gtk_toggle_button_get_active((GtkToggleButton*) widget)) + draw_state->draw_block_outlines = true; + else + draw_state->draw_block_outlines = false; + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } // Callback function for Block Text checkbox -static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { - t_draw_state* draw_state = get_draw_state_vars(); - - // assign corresponding bool value to draw_state->draw_block_text - if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) - draw_state->draw_block_text = true; - else - draw_state->draw_block_text = false; - - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +static void set_block_text(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/) { + t_draw_state *draw_state = get_draw_state_vars(); + + // assign corresponding bool value to draw_state->draw_block_text + if (gtk_toggle_button_get_active((GtkToggleButton*) widget)) + draw_state->draw_block_text = true; + else + draw_state->draw_block_text = false; + + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } // Callback function for Clip Routing Util checkbox -static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { - t_draw_state* draw_state = get_draw_state_vars(); - - // assign corresponding bool value to draw_state->clip_routing_util - if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) - draw_state->clip_routing_util = true; - else - draw_state->clip_routing_util = false; - - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +static void clip_routing_util(GtkWidget *widget, gint /*response_id*/, + gpointer /*data*/) { + t_draw_state *draw_state = get_draw_state_vars(); + + // assign corresponding bool value to draw_state->clip_routing_util + if (gtk_toggle_button_get_active((GtkToggleButton*) widget)) + draw_state->clip_routing_util = true; + else + draw_state->clip_routing_util = false; + + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } // Callback function for NetMax Fanout checkbox -void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created net_max_fanout widget - * which is written in button.cpp */ - std::string button_name = "netMaxFanout"; - auto max_fanout = find_button(button_name.c_str()); - t_draw_state* draw_state = get_draw_state_vars(); - - //set draw_state->draw_net_max_fanout to its corresponding value in the ui - int new_value = gtk_spin_button_get_value_as_int((GtkSpinButton*)max_fanout); - draw_state->draw_net_max_fanout = new_value; - - //redraw - application.refresh_drawing(); +void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + /* this is the callback function for runtime created net_max_fanout widget + * which is written in button.cpp */ + std::string button_name = "netMaxFanout"; + auto max_fanout = find_button(button_name.c_str()); + t_draw_state *draw_state = get_draw_state_vars(); + + //set draw_state->draw_net_max_fanout to its corresponding value in the ui + int new_value = gtk_spin_button_get_value_as_int( + (GtkSpinButton*) max_fanout); + draw_state->draw_net_max_fanout = new_value; + + //redraw + application.refresh_drawing(); } -bool get_manual_move_flag() { - GObject* manual_moves = application.get_object("manualMove"); - return gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); +bool get_manual_move_flag() { + GObject *manual_moves = application.get_object("manualMove"); + return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); } -static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - t_draw_state* draw_state = get_draw_state_vars(); +static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, + gpointer /*data*/) { + t_draw_state *draw_state = get_draw_state_vars(); - draw_state->forced_pause = true; + draw_state->forced_pause = true; } static void run_graphics_commands(std::string commands) { - //A very simmple command interpreter for scripting graphics - t_draw_state* draw_state = get_draw_state_vars(); - - t_draw_state backup_draw_state = *draw_state; - - std::vector> cmds; - for (std::string raw_cmd : vtr::split(commands, ";")) { - cmds.push_back(vtr::split(raw_cmd)); - } - - for (auto& cmd : cmds) { - VTR_ASSERT_MSG(cmd.size() > 0, "Expect non-empty graphics commands"); - - for (auto& item : cmd) { - VTR_LOG("%s ", item.c_str()); - } - VTR_LOG("\n"); - - if (cmd[0] == "save_graphics") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect filename after 'save_graphics'"); - - auto name_ext = vtr::split_ext(cmd[1]); - - //Replace {i} with the sequence number - std::string name = vtr::replace_all(name_ext[0], "{i}", std::to_string(draw_state->sequence_number)); - - save_graphics(/*extension=*/name_ext[1], /*filename=*/name); - VTR_LOG("Saving to %s\n", std::string(name + name_ext[1]).c_str()); - - } else if (cmd[0] == "set_macros") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect net draw state after 'set_macro'"); - draw_state->show_placement_macros = (e_draw_placement_macros)vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->show_placement_macros); - } else if (cmd[0] == "set_nets") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect net draw state after 'set_nets'"); - draw_state->show_nets = (e_draw_nets)vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->show_nets); - } else if (cmd[0] == "set_cpd") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect cpd draw state after 'set_cpd'"); - draw_state->show_crit_path = (e_draw_crit_path)vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->show_crit_path); - } else if (cmd[0] == "set_routing_util") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect routing util draw state after 'set_routing_util'"); - draw_state->show_routing_util = (e_draw_routing_util)vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->show_routing_util); - } else if (cmd[0] == "set_clip_routing_util") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect routing util draw state after 'set_routing_util'"); - draw_state->clip_routing_util = (bool)vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->clip_routing_util); - } else if (cmd[0] == "set_congestion") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect congestion draw state after 'set_congestion'"); - draw_state->show_congestion = (e_draw_congestion)vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->show_congestion); - } else if (cmd[0] == "set_draw_block_outlines") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect draw block outlines state after 'set_draw_block_outlines'"); - draw_state->draw_block_outlines = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->draw_block_outlines); - } else if (cmd[0] == "set_draw_block_text") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect draw block text state after 'set_draw_block_text'"); - draw_state->draw_block_text = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->draw_block_text); - } else if (cmd[0] == "set_draw_block_internals") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect draw state after 'set_draw_block_internals'"); - draw_state->show_blk_internal = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->show_blk_internal); - } else if (cmd[0] == "set_draw_net_max_fanout") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect maximum fanout after 'set_draw_net_max_fanout'"); - draw_state->draw_net_max_fanout = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int)draw_state->draw_net_max_fanout); - } else if (cmd[0] == "exit") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect exit code after 'exit'"); - exit(vtr::atoi(cmd[1])); - } else { - VPR_ERROR(VPR_ERROR_DRAW, vtr::string_fmt("Unrecognized graphics command '%s'", cmd[0].c_str()).c_str()); - } - } - - *draw_state = backup_draw_state; //Restor original draw state - - //Advance the sequence number - ++draw_state->sequence_number; + //A very simmple command interpreter for scripting graphics + t_draw_state *draw_state = get_draw_state_vars(); + + t_draw_state backup_draw_state = *draw_state; + + std::vector> cmds; + for (std::string raw_cmd : vtr::split(commands, ";")) { + cmds.push_back(vtr::split(raw_cmd)); + } + + for (auto &cmd : cmds) { + VTR_ASSERT_MSG(cmd.size() > 0, "Expect non-empty graphics commands"); + + for (auto &item : cmd) { + VTR_LOG("%s ", item.c_str()); + } + VTR_LOG("\n"); + + if (cmd[0] == "save_graphics") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect filename after 'save_graphics'"); + + auto name_ext = vtr::split_ext(cmd[1]); + + //Replace {i} with the sequence number + std::string name = vtr::replace_all(name_ext[0], "{i}", + std::to_string(draw_state->sequence_number)); + + save_graphics(/*extension=*/name_ext[1], /*filename=*/name); + VTR_LOG("Saving to %s\n", std::string(name + name_ext[1]).c_str()); + + } else if (cmd[0] == "set_macros") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect net draw state after 'set_macro'"); + draw_state->show_placement_macros = + (e_draw_placement_macros) vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->show_placement_macros); + } else if (cmd[0] == "set_nets") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect net draw state after 'set_nets'"); + draw_state->show_nets = (e_draw_nets) vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->show_nets); + } else if (cmd[0] == "set_cpd") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect cpd draw state after 'set_cpd'"); + draw_state->show_crit_path = (e_draw_crit_path) vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->show_crit_path); + } else if (cmd[0] == "set_routing_util") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect routing util draw state after 'set_routing_util'"); + draw_state->show_routing_util = (e_draw_routing_util) vtr::atoi( + cmd[1]); + VTR_LOG("%d\n", (int )draw_state->show_routing_util); + } else if (cmd[0] == "set_clip_routing_util") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect routing util draw state after 'set_routing_util'"); + draw_state->clip_routing_util = (bool) vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->clip_routing_util); + } else if (cmd[0] == "set_congestion") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect congestion draw state after 'set_congestion'"); + draw_state->show_congestion = (e_draw_congestion) vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->show_congestion); + } else if (cmd[0] == "set_draw_block_outlines") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect draw block outlines state after 'set_draw_block_outlines'"); + draw_state->draw_block_outlines = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->draw_block_outlines); + } else if (cmd[0] == "set_draw_block_text") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect draw block text state after 'set_draw_block_text'"); + draw_state->draw_block_text = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->draw_block_text); + } else if (cmd[0] == "set_draw_block_internals") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect draw state after 'set_draw_block_internals'"); + draw_state->show_blk_internal = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->show_blk_internal); + } else if (cmd[0] == "set_draw_net_max_fanout") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect maximum fanout after 'set_draw_net_max_fanout'"); + draw_state->draw_net_max_fanout = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int )draw_state->draw_net_max_fanout); + } else if (cmd[0] == "exit") { + VTR_ASSERT_MSG(cmd.size() == 2, "Expect exit code after 'exit'"); + exit(vtr::atoi(cmd[1])); + } else { + VPR_ERROR(VPR_ERROR_DRAW, + vtr::string_fmt("Unrecognized graphics command '%s'", + cmd[0].c_str()).c_str()); + } + } + + *draw_state = backup_draw_state; //Restor original draw state + + //Advance the sequence number + ++draw_state->sequence_number; } /* This routine highlights the blocks affected in the latest move * * It highlights the old and new locations of the moved blocks * * It also highlights the moved block input and output terminals * * Currently, it is used in placer debugger when breakpoint is reached */ -void highlight_moved_block_and_its_terminals(const t_pl_blocks_to_be_moved& blocks_affected) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - - //clear all selected blocks - deselect_all(); - - //highlight the input/output terminals of the moved block - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(blocks_affected.moved_blocks[0].block_num), blocks_affected.moved_blocks[0].block_num); - - //highlight the old and new locations of the moved block - clear_colored_locations(); - set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, OLD_BLK_LOC_COLOR); - set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, NEW_BLK_LOC_COLOR); +void highlight_moved_block_and_its_terminals( + const t_pl_blocks_to_be_moved &blocks_affected) { + auto &cluster_ctx = g_vpr_ctx.clustering(); + + //clear all selected blocks + deselect_all(); + + //highlight the input/output terminals of the moved block + draw_highlight_blocks_color( + cluster_ctx.clb_nlist.block_type( + blocks_affected.moved_blocks[0].block_num), + blocks_affected.moved_blocks[0].block_num); + + //highlight the old and new locations of the moved block + clear_colored_locations(); + set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, + OLD_BLK_LOC_COLOR); + set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, + NEW_BLK_LOC_COLOR); } // pass in an (x,y,subtile) location and the color in which it should be drawn. // This overrides the color of any block placed in that location, and also applies if the location is empty. void set_draw_loc_color(t_pl_loc loc, ezgl::color clr) { - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->colored_locations.push_back(std::make_pair(loc, clr)); + t_draw_state *draw_state = get_draw_state_vars(); + draw_state->colored_locations.push_back(std::make_pair(loc, clr)); } // clear the colored_locations vector void clear_colored_locations() { - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->colored_locations.clear(); + t_draw_state *draw_state = get_draw_state_vars(); + draw_state->colored_locations.clear(); } // This routine takes in a (x,y) location. // If the input loc is marked in colored_locations vector, the function will return true and the correspnding color is sent back in loc_color // otherwise, the function returns false (the location isn't among the highlighted locations) -bool highlight_loc_with_specific_color(int x, int y, ezgl::color& loc_color) { - t_draw_state* draw_state = get_draw_state_vars(); - - //define a (x,y) location variable - t_pl_loc curr_loc; - curr_loc.x = x; - curr_loc.y = y; - - //search for the current location in the vector of colored locations - auto it = std::find_if(draw_state->colored_locations.begin(), draw_state->colored_locations.end(), [&curr_loc](const std::pair& vec_element) { return (vec_element.first.x == curr_loc.x && vec_element.first.y == curr_loc.y); }); - - if (it != draw_state->colored_locations.end()) { - /* found a colored location at the spot I am drawing * - * (currently used for drawing the current move). * - * This overrides any block color. */ - loc_color = it->second; - return true; - } - - return false; +bool highlight_loc_with_specific_color(int x, int y, ezgl::color &loc_color) { + t_draw_state *draw_state = get_draw_state_vars(); + + //define a (x,y) location variable + t_pl_loc curr_loc; + curr_loc.x = x; + curr_loc.y = y; + + //search for the current location in the vector of colored locations + auto it = std::find_if(draw_state->colored_locations.begin(), + draw_state->colored_locations.end(), + [&curr_loc](const std::pair &vec_element) { + return (vec_element.first.x == curr_loc.x + && vec_element.first.y == curr_loc.y); + }); + + if (it != draw_state->colored_locations.end()) { + /* found a colored location at the spot I am drawing * + * (currently used for drawing the current move). * + * This overrides any block color. */ + loc_color = it->second; + return true; + } + + return false; } #endif /* NO_GRAPHICS */ diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 311619585cf..cb8222ae284 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -1,9 +1,10 @@ #include "manual_moves.h" #include "move_utils.h" #include "globals.h" -//#include "draw_debug.h" #include "draw.h" #include "move_generator.h" +#include "buttons.h" +#include "move_utils.h" #ifndef NO_GRAPHICS @@ -12,332 +13,337 @@ ManualMovesGlobals manual_moves_global; void draw_manual_moves_window(std::string block_id) { - std::cout << "Entered function in different file" << std::endl; - - if(!manual_moves_global.mm_window_is_open) { + if (!manual_moves_global.mm_window_is_open) { manual_moves_global.mm_window_is_open = true; - //Window settings + //Window settings- manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position((GtkWindow*)manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); - gtk_window_set_title((GtkWindow*)manual_moves_global.manual_move_window, "Manual Moves Generator"); - gtk_widget_set_name(manual_moves_global.manual_move_window, "manualMovesWindow"); - - - GtkWidget* grid = gtk_grid_new(); - GtkWidget* block_entry = gtk_entry_new(); - gtk_entry_set_text((GtkEntry*)block_entry, block_id.c_str()); - GtkWidget* x_position_entry = gtk_entry_new(); - GtkWidget* y_position_entry = gtk_entry_new(); - GtkWidget* subtile_position_entry = gtk_entry_new(); - GtkWidget* block_label = gtk_label_new("Block ID/Block Name:"); - GtkWidget* to_label = gtk_label_new("To Location:"); - GtkWidget* x = gtk_label_new("x:"); - GtkWidget* y = gtk_label_new("y:"); - GtkWidget* subtile = gtk_label_new("Subtile:"); - - GtkWidget* calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); - std::cout << "In draw_mm_window: " << block_id << std::endl; - - //Add all to grid - gtk_grid_attach((GtkGrid*)grid, block_label, 0, 0, 1, 1); - gtk_grid_attach((GtkGrid*)grid, block_entry, 0, 1, 1, 1); - gtk_grid_attach((GtkGrid*)grid, to_label, 2, 0, 1, 1); - gtk_grid_attach((GtkGrid*)grid, x, 1, 1, 1, 1); - gtk_grid_attach((GtkGrid*)grid, x_position_entry, 2, 1, 1, 1); - gtk_grid_attach((GtkGrid*)grid, y, 1, 2, 1, 1); - gtk_grid_attach((GtkGrid*)grid, y_position_entry, 2, 2, 1, 1); - gtk_grid_attach((GtkGrid*)grid, subtile, 1, 3, 1, 1); - gtk_grid_attach((GtkGrid*)grid, subtile_position_entry, 2, 3, 1, 1); - gtk_grid_attach((GtkGrid*)grid, calculate_cost_button, 0, 4, 3, 1); //spans three columns - - //Set margins - gtk_widget_set_margin_bottom(grid, 20); - gtk_widget_set_margin_top(grid, 20); - gtk_widget_set_margin_start(grid, 20); - gtk_widget_set_margin_end(grid, 20); - gtk_widget_set_margin_bottom(block_label, 5); - gtk_widget_set_margin_bottom(to_label, 5); - gtk_widget_set_margin_top(calculate_cost_button, 15); - gtk_widget_set_margin_start(x, 13); - gtk_widget_set_margin_start(y, 13); - gtk_widget_set_halign(calculate_cost_button, GTK_ALIGN_CENTER); + gtk_window_set_position((GtkWindow*) manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*) manual_moves_global.manual_move_window, "Manual Moves Generator"); - g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); - - //connect signals - g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); + GtkWidget *grid = gtk_grid_new(); + GtkWidget *block_entry = gtk_entry_new(); + + if (manual_moves_global.user_highlighted_block) { + gtk_entry_set_text((GtkEntry*) block_entry, block_id.c_str()); + manual_moves_global.user_highlighted_block = false; + } + GtkWidget *x_position_entry = gtk_entry_new(); + GtkWidget *y_position_entry = gtk_entry_new(); + GtkWidget *subtile_position_entry = gtk_entry_new(); + GtkWidget *block_label = gtk_label_new("Block ID/Block Name:"); + GtkWidget *to_label = gtk_label_new("To Location:"); + GtkWidget *x = gtk_label_new("x:"); + GtkWidget *y = gtk_label_new("y:"); + GtkWidget *subtile = gtk_label_new("Subtile:"); + + GtkWidget *calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); + + //Add all to grid + gtk_grid_attach((GtkGrid*) grid, block_label, 0, 0, 1, 1); + gtk_grid_attach((GtkGrid*) grid, block_entry, 0, 1, 1, 1); + gtk_grid_attach((GtkGrid*) grid, to_label, 2, 0, 1, 1); + gtk_grid_attach((GtkGrid*) grid, x, 1, 1, 1, 1); + gtk_grid_attach((GtkGrid*) grid, x_position_entry, 2, 1, 1, 1); + gtk_grid_attach((GtkGrid*) grid, y, 1, 2, 1, 1); + gtk_grid_attach((GtkGrid*) grid, y_position_entry, 2, 2, 1, 1); + gtk_grid_attach((GtkGrid*) grid, subtile, 1, 3, 1, 1); + gtk_grid_attach((GtkGrid*) grid, subtile_position_entry, 2, 3, 1, 1); + gtk_grid_attach((GtkGrid*) grid, calculate_cost_button, 0, 4, 3, 1); //spans three columns + + //Set margins + gtk_widget_set_margin_bottom(grid, 20); + gtk_widget_set_margin_top(grid, 20); + gtk_widget_set_margin_start(grid, 20); + gtk_widget_set_margin_end(grid, 20); + gtk_widget_set_margin_bottom(block_label, 5); + gtk_widget_set_margin_bottom(to_label, 5); + gtk_widget_set_margin_top(calculate_cost_button, 15); + gtk_widget_set_margin_start(x, 13); + gtk_widget_set_margin_start(y, 13); + gtk_widget_set_halign(calculate_cost_button, GTK_ALIGN_CENTER); - gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); - gtk_widget_show_all(manual_moves_global.manual_move_window); - } + //connect signals + g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); + + gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); + gtk_widget_show_all(manual_moves_global.manual_move_window); + } } -void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { - +void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget *grid) { + int block_id; int x_location; int y_location; int subtile_location; bool valid_input = true; - auto& cluster_ctx = g_vpr_ctx.clustering(); - + + //Loading the context/data structures needed. + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_ctx = g_vpr_ctx.placement(); + //Getting entry values - GtkWidget* block_entry = gtk_grid_get_child_at((GtkGrid*)grid, 0, 1); - std::string block_id_string = gtk_entry_get_text((GtkEntry*)block_entry); - - if(string_is_a_number(block_id_string)) { //for block ID + GtkWidget *block_entry = gtk_grid_get_child_at((GtkGrid*) grid, 0, 1); + std::string block_id_string = gtk_entry_get_text((GtkEntry*) block_entry); + + if (string_is_a_number(block_id_string)) { //for block ID block_id = std::atoi(block_id_string.c_str()); - } - else { //for block name - block_id = size_t(cluster_ctx.clb_nlist.find_block(gtk_entry_get_text((GtkEntry*)block_entry))); + } else { //for block name + block_id = size_t( + cluster_ctx.clb_nlist.find_block( + gtk_entry_get_text((GtkEntry*) block_entry))); } //if the block is not found - if((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id))) || (cluster_ctx.clb_nlist.find_blockblock_id) == BlockId::INVALID)) { + if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { invalid_breakpoint_entry_window("Invalid block ID/Name"); valid_input = false; } - GtkWidget* x_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 1); - GtkWidget* y_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 2); - GtkWidget* subtile_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 3); - - x_location = std::atoi(gtk_entry_get_text((GtkEntry*)x_position_entry)); - y_location = std::atoi(gtk_entry_get_text((GtkEntry*)y_position_entry)); - subtile_location = std::atoi(gtk_entry_get_text((GtkEntry*)subtile_position_entry)); + GtkWidget *x_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 1); + GtkWidget *y_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 2); + GtkWidget *subtile_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, + 2, 3); + x_location = std::atoi(gtk_entry_get_text((GtkEntry*) x_position_entry)); + y_location = std::atoi(gtk_entry_get_text((GtkEntry*) y_position_entry)); + subtile_location = std::atoi(gtk_entry_get_text((GtkEntry*) subtile_position_entry)); - //Check validity of the location (i.e. within bounds) - auto& device_ctx = g_vpr_ctx.device(); - if(x_location < 0 || x_location > int(device_ctx.grid.width())) { - invalid_breakpoint_entry_window("x value is out of bounds"); - valid_input = false; - } - if(y_location < 0 || y_location > int(device_ctx.grid.height())) { - invalid_breakpoint_entry_window("y value is out of bounds"); + //Function in move_utils.cpp that returns true if the location swap is valid + t_pl_loc to = t_pl_loc(x_location, y_location, subtile_location); + if (!is_legal_swap_to_location(ClusterBlockId(block_id), to)) { valid_input = false; } - - //Checking the subtile validity - if(subtile_location < 0 || subtile_location > int(device_ctx.grid[x_location][y_location].type->capacity)) { - invalid_breakpoint_entry_window("Invalid subtile value"); + //If the block requested is already in that location. + ClusterBlockId current_block = ClusterBlockId(block_id); + t_pl_loc current_block_loc = place_ctx.block_locs[current_block].loc; + if (x_location == current_block_loc.x && y_location == current_block_loc.y + && subtile_location == current_block_loc.sub_tile) { + invalid_breakpoint_entry_window( + "The block is currently in this location"); valid_input = false; } - //Checks if all fields from the user input window are complete. - if(std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { + if (std::string(gtk_entry_get_text((GtkEntry*) block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*) x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*) y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*) subtile_position_entry)).empty()) { invalid_breakpoint_entry_window("Not all fields are complete"); valid_input = false; - } + } - if(valid_input) { - + if (valid_input) { manual_moves_global.manual_move_info.valid_input = true; manual_moves_global.manual_move_info.blockID = block_id; manual_moves_global.manual_move_info.x_pos = x_location; manual_moves_global.manual_move_info.y_pos = y_location; manual_moves_global.manual_move_info.subtile = subtile_location; - - std::cout << "valid input: " << manual_moves_global.manual_move_info.valid_input << std::endl; - std::cout << "block id: " << manual_moves_global.manual_move_info.blockID << std::endl; - std::cout << "x location: " << manual_moves_global.manual_move_info.x_pos << std::endl; - std::cout << "y location: " << manual_moves_global.manual_move_info.y_pos << std::endl; - std::cout << "subtile: " << manual_moves_global.manual_move_info.subtile << std::endl; - - manual_moves_global.manual_move_info.to_location = t_pl_loc(manual_moves_global.manual_move_info.x_pos, manual_moves_global.manual_move_info.y_pos, manual_moves_global.manual_move_info.subtile); - //std::cout << "To location x: " << manual_moves_global.manual_move_info.to_location.x << std::endl; + manual_moves_global.manual_move_info.to_location = to; //Highlighting the block - ClusterBlockId clb_index = ClusterBlockId(block_id); - - //Unselects all blocks first - deselect_all(); + highlight_block_location(); - //Highlight block requested by user - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); - application.refresh_drawing(); + //Continues to move costs window. + GtkWidget *proceed = find_button("ProceedButton"); + ezgl::press_proceed(proceed, &application); - } - else { + } else { manual_moves_global.manual_move_info.valid_input = false; } - + } bool string_is_a_number(std::string block_id) { - for(size_t i = 0; i < block_id.size(); i++) { + for (size_t i = 0; i < block_id.size(); i++) { //Returns 0 if the string does not have characters from 0-9 - if(isdigit(block_id[i]) == 0) { + if (isdigit(block_id[i]) == 0) { return false; } } return true; } -ManualMovesInfo* get_manual_move_info() { - //returning the address to manual move info - return &manual_moves_global.manual_move_info; -} - ManualMovesGlobals* get_manual_moves_global() { return &manual_moves_global; } //Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/) { - - std::cout << "In propose move function" << std::endl; +e_create_move ManualMoveGenerator::propose_move( + t_pl_blocks_to_be_moved &blocks_affected, float /*rlim*/) { int block_id = manual_moves_global.manual_move_info.blockID; t_pl_loc to = manual_moves_global.manual_move_info.to_location; - - //std::cout << "In propose move function: " << to.x << ", " << to.y << ", " << to.sub_tile << std::endl; - ClusterBlockId b_from = ClusterBlockId(block_id); //Checking if the block was found - if(!b_from) { + if (!b_from) { return e_create_move::ABORT; //No movable block was found } - auto& place_ctx = g_vpr_ctx.placement(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& device_ctx = g_vpr_ctx.device(); + auto &place_ctx = g_vpr_ctx.placement(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &device_ctx = g_vpr_ctx.device(); //Gets the current location of the block to move. t_pl_loc from = place_ctx.block_locs[b_from].loc; - std::cout << "The block to move is at: " << from.x << ", " << from.y << std::endl; auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); auto grid_from_type = device_ctx.grid[from.x][from.y].type; VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); - //Retrieving the compressed block grid for this block type - const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; - + const auto &compressed_block_grid = + place_ctx.compressed_block_grids[cluster_from_type->index]; //Checking if the block has a compatible subtile. auto to_type = device_ctx.grid[to.x][to.y].type; auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); //No compatible subtile is found. - if(std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { + if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { return e_create_move::ABORT; } + /*std::cout << "The to subtile: " << to.sub_tile << std::endl; + for(auto itr = compatible_subtiles.begin(); itr != compatible_subtiles.end(); itr++) { + std::cout << *itr << std::endl; + }*/ + + e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; -} -//Checks if the are any compatible subtiles with the moving block type. -bool find_to_loc_manual_move(t_logical_block_type_ptr type, t_pl_loc& to) { - - //Retrieve the comporessed block grid for this block type - const auto& compressed_block_grid = g_vpr_ctx.placement().compressed_block_grids[type->index]; - auto to_type = g_vpr_ctx.device().grid[to.x][to.y].type; - auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); - //Checking for the to subtile in a vector. No compatible subtile was found - if(std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) != compatible_subtiles.end()) { - return false; - } - return true; } -void cost_summary() { - - std::cout << "\n"; - std::cout << "In cost summary window" << std::endl; - std::cout << "Delta cost: " << manual_moves_global.manual_move_info.delta_cost << std::endl; - std::cout << "Delta timing: " << manual_moves_global.manual_move_info.delta_timing << std::endl; - std::cout << "Delta bouding box: " << manual_moves_global.manual_move_info.delta_bounding_box << std::endl; - - //if(!manual_moves_global.cost_window_is_open) { - - //Window settings - GtkWidget* cost_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position((GtkWindow*)cost_window, GTK_WIN_POS_CENTER); - gtk_window_set_title((GtkWindow*)cost_window, "Move Costs"); - - //Creating grid and labels - GtkWidget* grid = gtk_grid_new(); - GtkWidget* title = gtk_label_new(NULL); - gtk_label_set_markup((GtkLabel*)title, "Move Costs and Outcomes"); - std::string delta_cost_label = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost); - GtkWidget* dc = gtk_label_new(delta_cost_label.c_str()); - std::string delta_bounding_box_label = "Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box); - GtkWidget* dbbc = gtk_label_new(delta_bounding_box_label.c_str()); - std::string delta_timing_label = "Delta Timing: " +std::to_string(manual_moves_global.manual_move_info.delta_timing); - GtkWidget* dtc = gtk_label_new(delta_timing_label.c_str()); +void cost_summary_dialog() { + + GtkWidget *dialog; + GtkWidget *content_area; + + //Creating the dialog window + dialog = gtk_dialog_new_with_buttons("Move Costs", + (GtkWindow*)manual_moves_global.manual_move_window, + GTK_DIALOG_DESTROY_WITH_PARENT, + ("Accept"), + GTK_RESPONSE_ACCEPT, + ("Reject"), + GTK_RESPONSE_REJECT, + NULL); + + gtk_widget_set_halign(gtk_dialog_get_action_area((GtkDialog*) dialog), GTK_ALIGN_CENTER); + + //Create elements for the dialog and printing costs to the user. + GtkWidget *title_label = gtk_label_new(NULL); + gtk_label_set_markup((GtkLabel*) title_label, "Move Costs and Outcomes"); + std::string delta_cost = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost) + " "; + GtkWidget *delta_cost_label = gtk_label_new(delta_cost.c_str()); + std::string delta_timing = " Delta Timing: " + std::to_string(manual_moves_global.manual_move_info.delta_timing) + " "; + GtkWidget *delta_timing_label = gtk_label_new(delta_timing.c_str()); + std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box) + " "; + GtkWidget *delta_bounding_box_label = gtk_label_new(delta_bounding_box.c_str()); std::string outcome = e_move_result_to_string(manual_moves_global.manual_move_info.placer_move_outcome); - std::string move_outcome_label = "Move outcome: " + outcome; - GtkWidget* mo = gtk_label_new(move_outcome_label.c_str()); - - //Adding buttons - GtkWidget* accept = gtk_button_new_with_label("Accept"); - GtkWidget* reject = gtk_button_new_with_label("Reject"); - - //Attach to grid - gtk_grid_attach((GtkGrid*)grid, title, 0, 0, 2, 1); - gtk_grid_attach((GtkGrid*)grid, dc, 0, 1, 2, 1); - gtk_grid_attach((GtkGrid*)grid, dbbc, 0, 2, 2, 1); - gtk_grid_attach((GtkGrid*)grid, dtc, 0, 3, 2, 1); - gtk_grid_attach((GtkGrid*)grid, mo, 0, 4, 2, 1); - gtk_grid_attach((GtkGrid*)grid, accept, 0, 5, 1, 1); - gtk_grid_attach((GtkGrid*)grid, reject, 1, 5, 1, 1); - - //Set margins - gtk_widget_set_halign(accept, GTK_ALIGN_CENTER); - gtk_widget_set_halign(reject, GTK_ALIGN_CENTER); - gtk_widget_set_margin_bottom(grid, 20); - gtk_widget_set_margin_top(grid, 20); - gtk_widget_set_margin_end(grid, 20); - gtk_widget_set_margin_start(grid, 20); - gtk_widget_set_margin_bottom(title, 15); - gtk_widget_set_margin_bottom(dc, 5); - gtk_widget_set_margin_bottom(dbbc, 5); - gtk_widget_set_margin_bottom(dtc, 5); - gtk_widget_set_margin_bottom(mo, 15); - - //Callback functions for the buttons. - g_signal_connect(accept, "clicked", G_CALLBACK(accept_manual_move_window), cost_window); - g_signal_connect(reject, "clicked", G_CALLBACK(reject_manual_move_window), cost_window); - - gtk_container_add(GTK_CONTAINER(cost_window), grid); - - if(manual_moves_global.mm_window_is_open) { - gtk_widget_show_all(cost_window); + std::string move_outcome = " Annealing Decision: " + outcome + " "; + GtkWidget *move_outcome_label = gtk_label_new(move_outcome.c_str()); + GtkWidget *space_label1 = gtk_label_new(" "); + GtkWidget *space_label2 = gtk_label_new(" "); + + //Attach elements to the content area of the dialog. + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_container_add(GTK_CONTAINER(content_area), title_label); + gtk_container_add(GTK_CONTAINER(content_area), space_label1); + gtk_container_add(GTK_CONTAINER(content_area), delta_cost_label); + gtk_container_add(GTK_CONTAINER(content_area), delta_timing_label); + gtk_container_add(GTK_CONTAINER(content_area), delta_bounding_box_label); + gtk_container_add(GTK_CONTAINER(content_area), move_outcome_label); + gtk_container_add(GTK_CONTAINER(content_area), space_label2); + + //Show the dialog with all the labels. + gtk_widget_show_all(dialog); + + //Update message if user accepts the move. + std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); + msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; + + //Waiting for the user to respond to return to try_swa function. + int result = gtk_dialog_run(GTK_DIALOG(dialog)); + switch(result) { + + //If the user accepts the manual move + case GTK_RESPONSE_ACCEPT: + manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + application.update_message(msg.c_str()); + break; + //If the user rejects the manual move + case GTK_RESPONSE_REJECT: + manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + application.update_message("Manual move was rejected"); + break; + default: + manual_moves_global.manual_move_info.user_move_outcome = ABORTED; + break; + } -} -void accept_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window) { + //Destroys the move outcome dialog. + gtk_widget_destroy(dialog); - std::cout << "User accepted manual move" << std::endl; - //User accepts the manual move, and windows are destroyed. - manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; - manual_moves_global.mm_window_is_open = false; - gtk_widget_destroy((GtkWidget*)cost_window); - gtk_widget_destroy(manual_moves_global.manual_move_window); } -void reject_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window) { +void highlight_block_location() { + auto& cluster_ctx = g_vpr_ctx.clustering(); + //Unselects all blocks first + deselect_all(); + //Highlighting the block + ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); + application.refresh_drawing(); +} - std::cout << "User rejected manual move" << std::endl; - //User rejects the manual move, and windows are destroyed. - manual_moves_global.manual_move_info.user_move_outcome = REJECTED; - manual_moves_global.mm_window_is_open = false; - gtk_widget_destroy((GtkWidget*)cost_window); - gtk_widget_destroy(manual_moves_global.manual_move_window); +//Updates ManualMovesInfo cost members +void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { + manual_moves_global.manual_move_info.delta_cost = d_cost; + manual_moves_global.manual_move_info.delta_timing = d_timing; + manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; + manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; } +//Manual move window turns false, the window is destroyed. void close_manual_moves_window() { manual_moves_global.mm_window_is_open = false; } +//Deactivates the toggle button once the windows close. +void deactivating_toggle_button() { + GObject *manual_move_toggle = application.get_object("manualMove"); + gtk_toggle_button_set_active((GtkToggleButton*) manual_move_toggle, FALSE); +} +/*void dialog_callback(GtkDialog* dialog, gint response_id, gpointer user_data) { + + //Update message if user accepts the move. + std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); + msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; + + switch(result) { + //If the user accepts the manual move + case GTK_RESPONSE_ACCEPT: + manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + application.update_message(msg.c_str()); + //close_manual_moves_window(); + break; + //If the user rejects the manual move + case GTK_RESPONSE_REJECT: + manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + application.update_message("Manual move was rejected"); + //close_manual_moves_window(); + break; + default: + manual_moves_global.manual_move_info.user_move_outcome = ABORTED; + break; + } + gtk_widget_destroy(GTK_WIDGET(dialog)); +}*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index cd9e33c37ef..714c9c20373 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -36,31 +36,31 @@ struct ManualMovesInfo { struct ManualMovesGlobals { ManualMovesInfo manual_move_info; - bool mm_window_is_open = false; GtkWidget* manual_move_window; - bool cost_window_is_open = false; + bool mm_window_is_open = false; + bool user_highlighted_block = false; }; -/** Manual Moves Generator, inherits from MoveGenerator **/ +/** Manual Moves Generator, inherits from MoveGenerator class **/ class ManualMoveGenerator: public MoveGenerator { public: //Evaluates if move is successful and legal or unable to do. e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/); }; -//extern ManualMovesGlobals manual_moves_global; /** manual moves functions **/ void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); bool string_is_a_number(std::string block_id); -void cost_summary(); -bool find_to_loc_manual_move(t_logical_block_type_ptr type, t_pl_loc& to); -ManualMovesInfo* get_manual_move_info(); +void cost_summary_dialog(); ManualMovesGlobals* get_manual_moves_global(); -void accept_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window); -void reject_manual_move_window(GtkWidget* /*widget*/, GtkWidget* cost_window); +void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); +void highlight_block_location(); + +//void dialog_callback(GtkDialog* dialog, gint response_id, gpointer user_data); +void deactivating_toggle_button(); diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index e89cf093807..85429dcc6fd 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -5,6 +5,9 @@ #include "vtr_random.h" +#include "draw_debug.h" +#include "draw.h" + //f_placer_breakpoint_reached is used to stop the placer when a breakpoint is reached. When this flag is true, it stops the placer after the current perturbation. Thus, when a breakpoint is reached, this flag is set to true. //Note: The flag is only effective if compiled with VTR_ENABLE_DEBUG_LOGGING bool f_placer_breakpoint_reached = false; @@ -447,9 +450,14 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& device_ctx = g_vpr_ctx.device(); auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.placement(); + GObject* manual_move_toggle = application.get_object("manualMove"); + if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { + if(gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle)) { + invalid_breakpoint_entry_window("Dimensions are out of bounds"); + } return false; } @@ -458,6 +466,9 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { + if(gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle)) { + invalid_breakpoint_entry_window("Blocks are not compatible"); + } return false; } // If the destination block is user constrained, abort this swap diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 4dedf3a938e..306f7058a0f 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -40,6 +40,7 @@ #include "read_place.h" #include "place_constraints.h" #include "manual_moves.h" +#include "buttons.h" #include "static_move_generator.h" #include "simpleRL_move_generator.h" @@ -94,8 +95,7 @@ using std::min; */ enum e_cost_methods { - NORMAL, - CHECK + NORMAL, CHECK }; constexpr float INVALID_DELAY = std::numeric_limits::quiet_NaN(); @@ -128,8 +128,8 @@ static vtr::vector bb_updated_before; * number of tracks in that direction; for other cost functions they * * will never be used. * */ -static float** chanx_place_cost_fac; //[0...device_ctx.grid.width()-2] -static float** chany_place_cost_fac; //[0...device_ctx.grid.height()-2] +static float **chanx_place_cost_fac; //[0...device_ctx.grid.width()-2] +static float **chany_place_cost_fac; //[0...device_ctx.grid.height()-2] /* The following arrays are used by the try_swap function for speed. */ /* [0...cluster_ctx.clb_nlist.nets().size()-1] */ @@ -149,14 +149,16 @@ static int num_ts_called = 0; * Multiplied to bounding box of a net to better estimate wire length * * for higher fanout nets. Each entry is the correction factor for the * * fanout index-1 */ -static const float cross_count[50] = {/* [0..49] */ 1.0, 1.0, 1.0, 1.0828, 1.1536, 1.2206, 1.2823, 1.3385, 1.3991, 1.4493, 1.4974, - 1.5455, 1.5937, 1.6418, 1.6899, 1.7304, 1.7709, 1.8114, 1.8519, 1.8924, - 1.9288, 1.9652, 2.0015, 2.0379, 2.0743, 2.1061, 2.1379, 2.1698, 2.2016, - 2.2334, 2.2646, 2.2958, 2.3271, 2.3583, 2.3895, 2.4187, 2.4479, 2.4772, - 2.5064, 2.5356, 2.5610, 2.5864, 2.6117, 2.6371, 2.6625, 2.6887, 2.7148, - 2.7410, 2.7671, 2.7933}; +static const float cross_count[50] = {/* [0..49] */1.0, 1.0, 1.0, 1.0828, + 1.1536, 1.2206, 1.2823, 1.3385, 1.3991, 1.4493, 1.4974, 1.5455, 1.5937, + 1.6418, 1.6899, 1.7304, 1.7709, 1.8114, 1.8519, 1.8924, 1.9288, 1.9652, + 2.0015, 2.0379, 2.0743, 2.1061, 2.1379, 2.1698, 2.2016, 2.2334, 2.2646, + 2.2958, 2.3271, 2.3583, 2.3895, 2.4187, 2.4479, 2.4772, 2.5064, 2.5356, + 2.5610, 2.5864, 2.6117, 2.6371, 2.6625, 2.6887, 2.7148, 2.7410, 2.7671, + 2.7933 }; -std::unique_ptr f_move_stats_file(nullptr, vtr::fclose); +std::unique_ptr f_move_stats_file(nullptr, + vtr::fclose); #ifdef VTR_ENABLE_DEBUG_LOGGIING # define LOG_MOVE_STATS_HEADER() \ @@ -236,14 +238,13 @@ static void print_clb_placement(const char* fname); #endif static void alloc_and_load_placement_structs(float place_cost_exp, - const t_placer_opts& placer_opts, - t_direct_inf* directs, - int num_directs); + const t_placer_opts &placer_opts, t_direct_inf *directs, + int num_directs); static void alloc_and_load_try_swap_structs(); static void free_try_swap_structs(); -static void free_placement_structs(const t_placer_opts& placer_opts); +static void free_placement_structs(const t_placer_opts &placer_opts); static void alloc_and_load_for_fast_cost_update(float place_cost_exp); @@ -254,246 +255,229 @@ static double comp_bb_cost(e_cost_methods method); static void update_move_nets(int num_nets_affected); static void reset_move_nets(int num_nets_affected); -static e_move_result try_swap(const t_annealing_state* state, - t_placer_costs* costs, - MoveGenerator& move_generator, - ManualMoveGenerator& manual_move_generator, - SetupTimingInfo* timing_info, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - t_pl_blocks_to_be_moved& blocks_affected, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - const t_placer_opts& placer_opts, - MoveTypeStat& move_type_stat, - const t_place_algorithm& place_algorithm, - float timing_bb_factor); - -static void check_place(const t_placer_costs& costs, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - const t_place_algorithm& place_algorithm); - -static int check_placement_costs(const t_placer_costs& costs, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - const t_place_algorithm& place_algorithm); +static e_move_result try_swap(const t_annealing_state *state, + t_placer_costs *costs, MoveGenerator &move_generator, + ManualMoveGenerator &manual_move_generator, + SetupTimingInfo *timing_info, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + t_pl_blocks_to_be_moved &blocks_affected, + const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, + PlacerSetupSlacks *setup_slacks, const t_placer_opts &placer_opts, + MoveTypeStat &move_type_stat, const t_place_algorithm &place_algorithm, + float timing_bb_factor); + +static void check_place(const t_placer_costs &costs, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, + const t_place_algorithm &place_algorithm); + +static int check_placement_costs(const t_placer_costs &costs, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, + const t_place_algorithm &place_algorithm); static int check_placement_consistency(); static int check_block_placement_consistency(); static int check_macro_placement_consistency(); -static float starting_t(const t_annealing_state* state, - t_placer_costs* costs, - t_annealing_sched annealing_sched, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - SetupTimingInfo* timing_info, - MoveGenerator& move_generator, - ManualMoveGenerator& manual_move_generator, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - t_pl_blocks_to_be_moved& blocks_affected, - const t_placer_opts& placer_opts, - MoveTypeStat& move_type_stat); +static float starting_t(const t_annealing_state *state, t_placer_costs *costs, + t_annealing_sched annealing_sched, const PlaceDelayModel *delay_model, + PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, + SetupTimingInfo *timing_info, MoveGenerator &move_generator, + ManualMoveGenerator &manual_move_generator, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + t_pl_blocks_to_be_moved &blocks_affected, + const t_placer_opts &placer_opts, MoveTypeStat &move_type_stat); static int count_connections(); static double recompute_bb_cost(); -static void commit_td_cost(const t_pl_blocks_to_be_moved& blocks_affected); +static void commit_td_cost(const t_pl_blocks_to_be_moved &blocks_affected); -static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected); +static void revert_td_cost(const t_pl_blocks_to_be_moved &blocks_affected); -static void invalidate_affected_connections(const t_pl_blocks_to_be_moved& blocks_affected, - ClusteredPinTimingInvalidator* pin_tedges_invalidator, - TimingInfo* timing_info); +static void invalidate_affected_connections( + const t_pl_blocks_to_be_moved &blocks_affected, + ClusteredPinTimingInvalidator *pin_tedges_invalidator, + TimingInfo *timing_info); -static bool driven_by_moved_block(const ClusterNetId net, const t_pl_blocks_to_be_moved& blocks_affected); +static bool driven_by_moved_block(const ClusterNetId net, + const t_pl_blocks_to_be_moved &blocks_affected); -static float analyze_setup_slack_cost(const PlacerSetupSlacks* setup_slacks); +static float analyze_setup_slack_cost(const PlacerSetupSlacks *setup_slacks); static e_move_result assess_swap(double delta_c, double t); -static void get_non_updateable_bb(ClusterNetId net_id, t_bb* bb_coord_new); +static void get_non_updateable_bb(ClusterNetId net_id, t_bb *bb_coord_new); -static void update_bb(ClusterNetId net_id, t_bb* bb_coord_new, t_bb* bb_edge_new, int xold, int yold, int xnew, int ynew); +static void update_bb(ClusterNetId net_id, t_bb *bb_coord_new, + t_bb *bb_edge_new, int xold, int yold, int xnew, int ynew); -static int find_affected_nets_and_update_costs(const t_place_algorithm& place_algorithm, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - t_pl_blocks_to_be_moved& blocks_affected, - double& bb_delta_c, - double& timing_delta_c); +static int find_affected_nets_and_update_costs( + const t_place_algorithm &place_algorithm, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, + t_pl_blocks_to_be_moved &blocks_affected, double &bb_delta_c, + double &timing_delta_c); -static void record_affected_net(const ClusterNetId net, int& num_affected_nets); +static void record_affected_net(const ClusterNetId net, int &num_affected_nets); static void update_net_bb(const ClusterNetId net, - const t_pl_blocks_to_be_moved& blocks_affected, - int iblk, - const ClusterBlockId blk, - const ClusterPinId blk_pin); -static void update_td_delta_costs(const PlaceDelayModel* delay_model, - const PlacerCriticalities& criticalities, - const ClusterNetId net, - const ClusterPinId pin, - t_pl_blocks_to_be_moved& blocks_affected, - double& delta_timing_cost); + const t_pl_blocks_to_be_moved &blocks_affected, int iblk, + const ClusterBlockId blk, const ClusterPinId blk_pin); +static void update_td_delta_costs(const PlaceDelayModel *delay_model, + const PlacerCriticalities &criticalities, const ClusterNetId net, + const ClusterPinId pin, t_pl_blocks_to_be_moved &blocks_affected, + double &delta_timing_cost); -static double get_net_cost(ClusterNetId net_id, t_bb* bb_ptr); +static double get_net_cost(ClusterNetId net_id, t_bb *bb_ptr); -static void get_bb_from_scratch(ClusterNetId net_id, t_bb* coords, t_bb* num_on_edges); +static void get_bb_from_scratch(ClusterNetId net_id, t_bb *coords, + t_bb *num_on_edges); -static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb* bbptr); +static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb *bbptr); static void free_try_swap_arrays(); -static void outer_loop_update_timing_info(const t_placer_opts& placer_opts, - t_placer_costs* costs, - int num_connections, - float crit_exponent, - int* outer_crit_iter_count, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - SetupTimingInfo* timing_info); - -static void placement_inner_loop(const t_annealing_state* state, - const t_placer_opts& placer_opts, - int inner_recompute_limit, - t_placer_statistics* stats, - t_placer_costs* costs, - int* moves_since_cost_recompute, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - MoveGenerator& move_generator, - ManualMoveGenerator& manual_move_generator, - t_pl_blocks_to_be_moved& blocks_affected, - SetupTimingInfo* timing_info, - const t_place_algorithm& place_algorithm, - MoveTypeStat& move_type_stat, - float timing_bb_factor); - -static void recompute_costs_from_scratch(const t_placer_opts& placer_opts, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - t_placer_costs* costs); - -static void generate_post_place_timing_reports(const t_placer_opts& placer_opts, - const t_analysis_opts& analysis_opts, - const SetupTimingInfo& timing_info, - const PlacementDelayCalculator& delay_calc); +static void outer_loop_update_timing_info(const t_placer_opts &placer_opts, + t_placer_costs *costs, int num_connections, float crit_exponent, + int *outer_crit_iter_count, const PlaceDelayModel *delay_model, + PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + SetupTimingInfo *timing_info); + +static void placement_inner_loop(const t_annealing_state *state, + const t_placer_opts &placer_opts, int inner_recompute_limit, + t_placer_statistics *stats, t_placer_costs *costs, + int *moves_since_cost_recompute, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, + PlacerSetupSlacks *setup_slacks, MoveGenerator &move_generator, + ManualMoveGenerator &manual_move_generator, + t_pl_blocks_to_be_moved &blocks_affected, SetupTimingInfo *timing_info, + const t_place_algorithm &place_algorithm, MoveTypeStat &move_type_stat, + float timing_bb_factor); + +static void recompute_costs_from_scratch(const t_placer_opts &placer_opts, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, t_placer_costs *costs); + +static void generate_post_place_timing_reports(const t_placer_opts &placer_opts, + const t_analysis_opts &analysis_opts, + const SetupTimingInfo &timing_info, + const PlacementDelayCalculator &delay_calc); //calculate the agent's reward and the total process outcome -static void calculate_reward_and_process_outcome(const t_placer_opts& placer_opts, const MoveOutcomeStats& move_outcome_stats, const double& delta_c, float timing_bb_factor, MoveGenerator& move_generator); +static void calculate_reward_and_process_outcome( + const t_placer_opts &placer_opts, + const MoveOutcomeStats &move_outcome_stats, const double &delta_c, + float timing_bb_factor, MoveGenerator &move_generator); static void print_place_status_header(); -static void print_place_status(const t_annealing_state& state, - const t_placer_statistics& stats, - float elapsed_sec, - float cpd, - float sTNS, - float sWNS, - size_t tot_moves); +static void print_place_status(const t_annealing_state &state, + const t_placer_statistics &stats, float elapsed_sec, float cpd, + float sTNS, float sWNS, size_t tot_moves); static void print_resources_utilization(); -static void print_placement_swaps_stats(const t_annealing_state& state); +static void print_placement_swaps_stats(const t_annealing_state &state); -static void print_placement_move_types_stats(const MoveTypeStat& move_type_stat); +static void print_placement_move_types_stats( + const MoveTypeStat &move_type_stat); /*****************************************************************************/ -void try_place(const t_placer_opts& placer_opts, - t_annealing_sched annealing_sched, - const t_router_opts& router_opts, - const t_analysis_opts& analysis_opts, - t_chan_width_dist chan_width_dist, - t_det_routing_arch* det_routing_arch, - std::vector& segment_inf, - t_direct_inf* directs, - int num_directs) { - /* Does almost all the work of placing a circuit. Width_fac gives the * - * width of the widest channel. Place_cost_exp says what exponent the * - * width should be taken to when calculating costs. This allows a * - * greater bias for anisotropic architectures. */ - auto& device_ctx = g_vpr_ctx.device(); - auto& atom_ctx = g_vpr_ctx.atom(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_move_ctx = g_placer_ctx.mutable_move(); - - const auto& p_timing_ctx = g_placer_ctx.timing(); - const auto& p_runtime_ctx = g_placer_ctx.runtime(); - - auto& timing_ctx = g_vpr_ctx.timing(); - auto pre_place_timing_stats = timing_ctx.stats; - - int tot_iter, moves_since_cost_recompute, width_fac, num_connections, - outer_crit_iter_count, inner_recompute_limit; - float first_crit_exponent, first_rlim, first_t; - int first_move_lim; - - t_placer_costs costs(placer_opts.place_algorithm); - - tatum::TimingPathInfo critical_path; - float sTNS = NAN; - float sWNS = NAN; - - char msg[vtr::bufsize]; - t_placer_statistics stats; - - t_placement_checkpoint placement_checkpoint; - - std::shared_ptr timing_info; - std::shared_ptr placement_delay_calc; - std::unique_ptr place_delay_model; - std::unique_ptr move_generator; - std::unique_ptr move_generator2; - std::unique_ptr manual_move_generator; - std::unique_ptr placer_setup_slacks; - - std::unique_ptr placer_criticalities; - std::unique_ptr pin_timing_invalidator; - - t_pl_blocks_to_be_moved blocks_affected(cluster_ctx.clb_nlist.blocks().size()); - - /* Allocated here because it goes into timing critical code where each memory allocation is expensive */ - IntraLbPbPinLookup pb_gpin_lookup(device_ctx.logical_block_types); - - /* init file scope variables */ - num_swap_rejected = 0; - num_swap_accepted = 0; - num_swap_aborted = 0; - num_ts_called = 0; - - if (placer_opts.place_algorithm.is_timing_driven()) { - /*do this before the initial placement to avoid messing up the initial placement */ - place_delay_model = alloc_lookups_and_delay_model(chan_width_dist, placer_opts, router_opts, det_routing_arch, segment_inf, directs, num_directs); - - if (isEchoFileEnabled(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)) { - place_delay_model->dump_echo(getEchoFileName(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)); - } - } - - int move_lim = 1; - move_lim = (int)(annealing_sched.inner_num * pow(cluster_ctx.clb_nlist.blocks().size(), 1.3333)); - - //create the move generator based on the chosen strategy - create_move_generators(move_generator, move_generator2, placer_opts, move_lim); - - width_fac = placer_opts.place_chan_width; - - init_chan(width_fac, chan_width_dist); - - alloc_and_load_placement_structs(placer_opts.place_cost_exp, placer_opts, - directs, num_directs); - - vtr::ScopedStartFinishTimer timer("Placement"); - - initial_placement(placer_opts.pad_loc_type, placer_opts.constraints_file.c_str()); +void try_place(const t_placer_opts &placer_opts, + t_annealing_sched annealing_sched, const t_router_opts &router_opts, + const t_analysis_opts &analysis_opts, t_chan_width_dist chan_width_dist, + t_det_routing_arch *det_routing_arch, + std::vector &segment_inf, t_direct_inf *directs, + int num_directs) { + /* Does almost all the work of placing a circuit. Width_fac gives the * + * width of the widest channel. Place_cost_exp says what exponent the * + * width should be taken to when calculating costs. This allows a * + * greater bias for anisotropic architectures. */ + auto &device_ctx = g_vpr_ctx.device(); + auto &atom_ctx = g_vpr_ctx.atom(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_move_ctx = g_placer_ctx.mutable_move(); + + const auto &p_timing_ctx = g_placer_ctx.timing(); + const auto &p_runtime_ctx = g_placer_ctx.runtime(); + + auto &timing_ctx = g_vpr_ctx.timing(); + auto pre_place_timing_stats = timing_ctx.stats; + int tot_iter, moves_since_cost_recompute, width_fac, num_connections, + outer_crit_iter_count, inner_recompute_limit; + float first_crit_exponent, first_rlim, first_t; + int first_move_lim; + + t_placer_costs costs(placer_opts.place_algorithm); + + tatum::TimingPathInfo critical_path; + float sTNS = NAN; + float sWNS = NAN; + + char msg[vtr::bufsize]; + t_placer_statistics stats; + + t_placement_checkpoint placement_checkpoint; + + std::shared_ptr timing_info; + std::shared_ptr placement_delay_calc; + std::unique_ptr place_delay_model; + std::unique_ptr move_generator; + std::unique_ptr move_generator2; + std::unique_ptr manual_move_generator; + std::unique_ptr placer_setup_slacks; + + std::unique_ptr placer_criticalities; + std::unique_ptr pin_timing_invalidator; + + t_pl_blocks_to_be_moved blocks_affected( + cluster_ctx.clb_nlist.blocks().size()); + + /* Allocated here because it goes into timing critical code where each memory allocation is expensive */ + IntraLbPbPinLookup pb_gpin_lookup(device_ctx.logical_block_types); + + /* init file scope variables */ + num_swap_rejected = 0; + num_swap_accepted = 0; + num_swap_aborted = 0; + num_ts_called = 0; + + if (placer_opts.place_algorithm.is_timing_driven()) { + /*do this before the initial placement to avoid messing up the initial placement */ + place_delay_model = alloc_lookups_and_delay_model(chan_width_dist, + placer_opts, router_opts, det_routing_arch, segment_inf, + directs, num_directs); + + if (isEchoFileEnabled(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)) { + place_delay_model->dump_echo( + getEchoFileName(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)); + } + } + + int move_lim = 1; + move_lim = (int) (annealing_sched.inner_num + * pow(cluster_ctx.clb_nlist.blocks().size(), 1.3333)); + + //create the move generator based on the chosen strategy + create_move_generators(move_generator, move_generator2, placer_opts, + move_lim); + + width_fac = placer_opts.place_chan_width; + + init_chan(width_fac, chan_width_dist); + + alloc_and_load_placement_structs(placer_opts.place_cost_exp, placer_opts, + directs, num_directs); + + vtr::ScopedStartFinishTimer timer("Placement"); + + initial_placement(placer_opts.pad_loc_type, + placer_opts.constraints_file.c_str()); #ifdef ENABLE_ANALYTIC_PLACE /* @@ -507,197 +491,218 @@ void try_place(const t_placer_opts& placer_opts, } #endif /* ENABLE_ANALYTIC_PLACE */ - // Update physical pin values - for (auto block_id : cluster_ctx.clb_nlist.blocks()) { - place_sync_external_block_connections(block_id); - } - - init_draw_coords((float)width_fac); - //Enables fast look-up of atom pins connect to CLB pins - ClusteredPinAtomPinsLookup netlist_pin_lookup(cluster_ctx.clb_nlist, atom_ctx.nlist, pb_gpin_lookup); - - /* Gets initial cost and loads bounding boxes. */ - - if (placer_opts.place_algorithm.is_timing_driven()) { - costs.bb_cost = comp_bb_cost(NORMAL); - - first_crit_exponent = placer_opts.td_place_exp_first; /*this will be modified when rlim starts to change */ - - num_connections = count_connections(); - VTR_LOG("\n"); - VTR_LOG("There are %d point to point connections in this circuit.\n", num_connections); - VTR_LOG("\n"); - - //Update the point-to-point delays from the initial placement - comp_td_connection_delays(place_delay_model.get()); - - /* - * Initialize timing analysis - */ - placement_delay_calc = std::make_shared(atom_ctx.nlist, atom_ctx.lookup, p_timing_ctx.connection_delay); - placement_delay_calc->set_tsu_margin_relative(placer_opts.tsu_rel_margin); - placement_delay_calc->set_tsu_margin_absolute(placer_opts.tsu_abs_margin); - - timing_info = make_setup_timing_info(placement_delay_calc, placer_opts.timing_update_type); - - placer_setup_slacks = std::make_unique(cluster_ctx.clb_nlist, netlist_pin_lookup); - - placer_criticalities = std::make_unique(cluster_ctx.clb_nlist, netlist_pin_lookup); - - pin_timing_invalidator = std::make_unique(cluster_ctx.clb_nlist, - netlist_pin_lookup, - atom_ctx.nlist, - atom_ctx.lookup, - *timing_info->timing_graph()); - //First time compute timing and costs, compute from scratch - PlaceCritParams crit_params; - crit_params.crit_exponent = first_crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - initialize_timing_info(crit_params, - place_delay_model.get(), - placer_criticalities.get(), - placer_setup_slacks.get(), - pin_timing_invalidator.get(), - timing_info.get(), - &costs); - - critical_path = timing_info->least_slack_critical_path(); - - /* Write out the initial timing echo file */ - if (isEchoFileEnabled(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH)) { - tatum::write_echo(getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH), - *timing_ctx.graph, *timing_ctx.constraints, *placement_delay_calc, timing_info->analyzer()); - - tatum::NodeId debug_tnode = id_or_pin_name_to_tnode(analysis_opts.echo_dot_timing_graph_node); - write_setup_timing_graph_dot(getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH) + std::string(".dot"), - *timing_info, debug_tnode); - } - - outer_crit_iter_count = 1; - - /* Initialize the normalization factors. Calling costs.update_norm_factors() * - * here would fail the golden results of strong_sdc benchmark */ - costs.timing_cost_norm = 1 / costs.timing_cost; - costs.bb_cost_norm = 1 / costs.bb_cost; - costs.cost = 1; - } else { - VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); - - /* Total cost is the same as wirelength cost */ - costs.bb_cost = comp_bb_cost(NORMAL); - costs.cost = costs.bb_cost; - - /* Timing cost and normalization factors are not used */ - costs.timing_cost = INVALID_COST; - costs.timing_cost_norm = INVALID_COST; - costs.bb_cost_norm = INVALID_COST; - - /* Other initializations */ - outer_crit_iter_count = 0; - num_connections = 0; - first_crit_exponent = 0; - } - - //Sanity check that initial placement is legal - check_place(costs, place_delay_model.get(), placer_criticalities.get(), placer_opts.place_algorithm); - - //Initial pacement statistics - VTR_LOG("Initial placement cost: %g bb_cost: %g td_cost: %g\n", - costs.cost, costs.bb_cost, costs.timing_cost); - if (placer_opts.place_algorithm.is_timing_driven()) { - VTR_LOG("Initial placement estimated Critical Path Delay (CPD): %g ns\n", - 1e9 * critical_path.delay()); - VTR_LOG("Initial placement estimated setup Total Negative Slack (sTNS): %g ns\n", - 1e9 * timing_info->setup_total_negative_slack()); - VTR_LOG("Initial placement estimated setup Worst Negative Slack (sWNS): %g ns\n", - 1e9 * timing_info->setup_worst_negative_slack()); - VTR_LOG("\n"); - - VTR_LOG("Initial placement estimated setup slack histogram:\n"); - print_histogram(create_setup_slack_histogram(*timing_info->setup_analyzer())); - } - size_t num_macro_members = 0; - for (auto& macro : g_vpr_ctx.placement().pl_macros) { - num_macro_members += macro.members.size(); - } - VTR_LOG("Placement contains %zu placement macros involving %zu blocks (average macro size %f)\n", g_vpr_ctx.placement().pl_macros.size(), num_macro_members, float(num_macro_members) / g_vpr_ctx.placement().pl_macros.size()); - VTR_LOG("\n"); - - sprintf(msg, "Initial Placement. Cost: %g BB Cost: %g TD Cost %g \t Channel Factor: %d", - costs.cost, costs.bb_cost, costs.timing_cost, width_fac); - //Draw the initial placement - update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); - - if (placer_opts.placement_saves_per_temperature >= 1) { - std::string filename = vtr::string_fmt("placement_%03d_%03d.place", 0, 0); - VTR_LOG("Saving initial placement to file: %s\n", filename.c_str()); - print_place(nullptr, nullptr, filename.c_str()); - } - - first_move_lim = get_initial_move_lim(placer_opts, annealing_sched); - - if (placer_opts.inner_loop_recompute_divider != 0) { - inner_recompute_limit = (int)(0.5 + (float)first_move_lim / (float)placer_opts.inner_loop_recompute_divider); - } else { - /*don't do an inner recompute */ - inner_recompute_limit = first_move_lim + 1; - } - - /* calculate the number of moves in the quench that we should recompute timing after based on the value of * - * the commandline option quench_recompute_divider */ - int quench_recompute_limit; - if (placer_opts.quench_recompute_divider != 0) { - quench_recompute_limit = (int)(0.5 + (float)move_lim / (float)placer_opts.quench_recompute_divider); - } else { - /*don't do an quench recompute */ - quench_recompute_limit = first_move_lim + 1; - } - - //allocate helper vectors that are used by many move generators - place_move_ctx.X_coord.resize(10, 0); - place_move_ctx.Y_coord.resize(10, 0); - - //allocate move type statistics vectors - MoveTypeStat move_type_stat; - move_type_stat.num_moves.resize(placer_opts.place_static_move_prob.size(), 0); - move_type_stat.accepted_moves.resize(placer_opts.place_static_move_prob.size(), 0); - move_type_stat.aborted_moves.resize(placer_opts.place_static_move_prob.size(), 0); - - /* Get the first range limiter */ - first_rlim = (float)max(device_ctx.grid.width() - 1, device_ctx.grid.height() - 1); - place_move_ctx.first_rlim = first_rlim; - - /* Set the temperature high so essentially all swaps will be accepted */ - /* when trying to determine the starting temp for placement inner loop. */ - first_t = HUGE_POSITIVE_FLOAT; - - t_annealing_state state(annealing_sched, first_t, first_rlim, first_move_lim, first_crit_exponent); - - /* Update the starting temperature for placement annealing to a more appropriate value */ - state.t = starting_t(&state, - &costs, - annealing_sched, - place_delay_model.get(), - placer_criticalities.get(), - placer_setup_slacks.get(), - timing_info.get(), - *move_generator, - *manual_move_generator, - pin_timing_invalidator.get(), - blocks_affected, - placer_opts, - move_type_stat); - - if (!placer_opts.move_stats_file.empty()) { - f_move_stats_file = std::unique_ptr(vtr::fopen(placer_opts.move_stats_file.c_str(), "w"), vtr::fclose); - LOG_MOVE_STATS_HEADER(); - } - - tot_iter = 0; - moves_since_cost_recompute = 0; - - bool skip_anneal = false; + // Update physical pin values + for (auto block_id : cluster_ctx.clb_nlist.blocks()) { + place_sync_external_block_connections(block_id); + } + + init_draw_coords((float) width_fac); + //Enables fast look-up of atom pins connect to CLB pins + ClusteredPinAtomPinsLookup netlist_pin_lookup(cluster_ctx.clb_nlist, + atom_ctx.nlist, pb_gpin_lookup); + + /* Gets initial cost and loads bounding boxes. */ + + if (placer_opts.place_algorithm.is_timing_driven()) { + costs.bb_cost = comp_bb_cost(NORMAL); + + first_crit_exponent = placer_opts.td_place_exp_first; /*this will be modified when rlim starts to change */ + + num_connections = count_connections(); + VTR_LOG("\n"); + VTR_LOG("There are %d point to point connections in this circuit.\n", + num_connections); + VTR_LOG("\n"); + + //Update the point-to-point delays from the initial placement + comp_td_connection_delays(place_delay_model.get()); + + /* + * Initialize timing analysis + */ + placement_delay_calc = std::make_shared( + atom_ctx.nlist, atom_ctx.lookup, p_timing_ctx.connection_delay); + placement_delay_calc->set_tsu_margin_relative( + placer_opts.tsu_rel_margin); + placement_delay_calc->set_tsu_margin_absolute( + placer_opts.tsu_abs_margin); + + timing_info = make_setup_timing_info(placement_delay_calc, + placer_opts.timing_update_type); + + placer_setup_slacks = std::make_unique( + cluster_ctx.clb_nlist, netlist_pin_lookup); + + placer_criticalities = std::make_unique( + cluster_ctx.clb_nlist, netlist_pin_lookup); + + pin_timing_invalidator = + std::make_unique( + cluster_ctx.clb_nlist, netlist_pin_lookup, + atom_ctx.nlist, atom_ctx.lookup, + *timing_info->timing_graph()); + //First time compute timing and costs, compute from scratch + PlaceCritParams crit_params; + crit_params.crit_exponent = first_crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + initialize_timing_info(crit_params, place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + pin_timing_invalidator.get(), timing_info.get(), &costs); + + critical_path = timing_info->least_slack_critical_path(); + + /* Write out the initial timing echo file */ + if (isEchoFileEnabled(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH)) { + tatum::write_echo( + getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH), + *timing_ctx.graph, *timing_ctx.constraints, + *placement_delay_calc, timing_info->analyzer()); + + tatum::NodeId debug_tnode = id_or_pin_name_to_tnode( + analysis_opts.echo_dot_timing_graph_node); + write_setup_timing_graph_dot( + getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH) + + std::string(".dot"), *timing_info, debug_tnode); + } + + outer_crit_iter_count = 1; + + /* Initialize the normalization factors. Calling costs.update_norm_factors() * + * here would fail the golden results of strong_sdc benchmark */ + costs.timing_cost_norm = 1 / costs.timing_cost; + costs.bb_cost_norm = 1 / costs.bb_cost; + costs.cost = 1; + } else { + VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); + + /* Total cost is the same as wirelength cost */ + costs.bb_cost = comp_bb_cost(NORMAL); + costs.cost = costs.bb_cost; + + /* Timing cost and normalization factors are not used */ + costs.timing_cost = INVALID_COST; + costs.timing_cost_norm = INVALID_COST; + costs.bb_cost_norm = INVALID_COST; + + /* Other initializations */ + outer_crit_iter_count = 0; + num_connections = 0; + first_crit_exponent = 0; + } + + //Sanity check that initial placement is legal + check_place(costs, place_delay_model.get(), placer_criticalities.get(), + placer_opts.place_algorithm); + + //Initial pacement statistics + VTR_LOG("Initial placement cost: %g bb_cost: %g td_cost: %g\n", costs.cost, + costs.bb_cost, costs.timing_cost); + if (placer_opts.place_algorithm.is_timing_driven()) { + VTR_LOG( + "Initial placement estimated Critical Path Delay (CPD): %g ns\n", + 1e9 * critical_path.delay()); + VTR_LOG( + "Initial placement estimated setup Total Negative Slack (sTNS): %g ns\n", + 1e9 * timing_info->setup_total_negative_slack()); + VTR_LOG( + "Initial placement estimated setup Worst Negative Slack (sWNS): %g ns\n", + 1e9 * timing_info->setup_worst_negative_slack()); + VTR_LOG("\n"); + + VTR_LOG("Initial placement estimated setup slack histogram:\n"); + print_histogram( + create_setup_slack_histogram(*timing_info->setup_analyzer())); + } + size_t num_macro_members = 0; + for (auto ¯o : g_vpr_ctx.placement().pl_macros) { + num_macro_members += macro.members.size(); + } + VTR_LOG( + "Placement contains %zu placement macros involving %zu blocks (average macro size %f)\n", + g_vpr_ctx.placement().pl_macros.size(), num_macro_members, + float(num_macro_members) / g_vpr_ctx.placement().pl_macros.size()); + VTR_LOG("\n"); + + sprintf(msg, + "Initial Placement. Cost: %g BB Cost: %g TD Cost %g \t Channel Factor: %d", + costs.cost, costs.bb_cost, costs.timing_cost, width_fac); + //Draw the initial placement + update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); + + if (placer_opts.placement_saves_per_temperature >= 1) { + std::string filename = vtr::string_fmt("placement_%03d_%03d.place", 0, + 0); + VTR_LOG("Saving initial placement to file: %s\n", filename.c_str()); + print_place(nullptr, nullptr, filename.c_str()); + } + + first_move_lim = get_initial_move_lim(placer_opts, annealing_sched); + + if (placer_opts.inner_loop_recompute_divider != 0) { + inner_recompute_limit = (int) (0.5 + + (float) first_move_lim + / (float) placer_opts.inner_loop_recompute_divider); + } else { + /*don't do an inner recompute */ + inner_recompute_limit = first_move_lim + 1; + } + + /* calculate the number of moves in the quench that we should recompute timing after based on the value of * + * the commandline option quench_recompute_divider */ + int quench_recompute_limit; + if (placer_opts.quench_recompute_divider != 0) { + quench_recompute_limit = (int) (0.5 + + (float) move_lim + / (float) placer_opts.quench_recompute_divider); + } else { + /*don't do an quench recompute */ + quench_recompute_limit = first_move_lim + 1; + } + + //allocate helper vectors that are used by many move generators + place_move_ctx.X_coord.resize(10, 0); + place_move_ctx.Y_coord.resize(10, 0); + + //allocate move type statistics vectors + MoveTypeStat move_type_stat; + move_type_stat.num_moves.resize(placer_opts.place_static_move_prob.size(), + 0); + move_type_stat.accepted_moves.resize( + placer_opts.place_static_move_prob.size(), 0); + move_type_stat.aborted_moves.resize( + placer_opts.place_static_move_prob.size(), 0); + + /* Get the first range limiter */ + first_rlim = (float) max(device_ctx.grid.width() - 1, + device_ctx.grid.height() - 1); + place_move_ctx.first_rlim = first_rlim; + + /* Set the temperature high so essentially all swaps will be accepted */ + /* when trying to determine the starting temp for placement inner loop. */ + first_t = HUGE_POSITIVE_FLOAT; + + t_annealing_state state(annealing_sched, first_t, first_rlim, + first_move_lim, first_crit_exponent); + + /* Update the starting temperature for placement annealing to a more appropriate value */ + state.t = starting_t(&state, &costs, annealing_sched, + place_delay_model.get(), placer_criticalities.get(), + placer_setup_slacks.get(), timing_info.get(), *move_generator, + *manual_move_generator, pin_timing_invalidator.get(), + blocks_affected, placer_opts, move_type_stat); + + if (!placer_opts.move_stats_file.empty()) { + f_move_stats_file = std::unique_ptr( + vtr::fopen(placer_opts.move_stats_file.c_str(), "w"), + vtr::fclose); + LOG_MOVE_STATS_HEADER(); + } + + tot_iter = 0; + moves_since_cost_recompute = 0; + + bool skip_anneal = false; #ifdef ENABLE_ANALYTIC_PLACE // Analytic placer: When enabled, skip most of the annealing and go straight to quench @@ -706,178 +711,166 @@ void try_place(const t_placer_opts& placer_opts, skip_anneal = true; #endif /* ENABLE_ANALYTIC_PLACE */ - //RL agent state definition - e_agent_state agent_state = EARLY_IN_THE_ANNEAL; - - std::unique_ptr current_move_generator; - - //Define the timing bb weight factor for the agent's reward function - float timing_bb_factor = REWARD_BB_TIMING_RELATIVE_WEIGHT; - - if (skip_anneal == false) { - //Table header - VTR_LOG("\n"); - print_place_status_header(); - - /* Outer loop of the simulated annealing begins */ - do { - vtr::Timer temperature_timer; - - outer_loop_update_timing_info(placer_opts, - &costs, - num_connections, - state.crit_exponent, - &outer_crit_iter_count, - place_delay_model.get(), - placer_criticalities.get(), - placer_setup_slacks.get(), - pin_timing_invalidator.get(), - timing_info.get()); - - if (placer_opts.place_algorithm.is_timing_driven()) { - critical_path = timing_info->least_slack_critical_path(); - sTNS = timing_info->setup_total_negative_slack(); - sWNS = timing_info->setup_worst_negative_slack(); - - //see if we should save the current placement solution as a checkpoint - - if (placer_opts.place_checkpointing && agent_state == LATE_IN_THE_ANNEAL) { - save_placement_checkpoint_if_needed(placement_checkpoint, timing_info, costs, critical_path.delay()); - } - } - - //move the appropoiate move_generator to be the current used move generator - assign_current_move_generator(move_generator, move_generator2, agent_state, placer_opts, false, current_move_generator); - - //do a complete inner loop iteration - placement_inner_loop(&state, placer_opts, - inner_recompute_limit, &stats, - &costs, - &moves_since_cost_recompute, - pin_timing_invalidator.get(), - place_delay_model.get(), - placer_criticalities.get(), - placer_setup_slacks.get(), - *current_move_generator, - *manual_move_generator, - blocks_affected, - timing_info.get(), - placer_opts.place_algorithm, - move_type_stat, - timing_bb_factor); - - //move the update used move_generator to its original variable - update_move_generator(move_generator, move_generator2, agent_state, placer_opts, false, current_move_generator); - - tot_iter += state.move_lim; - ++state.num_temps; - - print_place_status(state, stats, temperature_timer.elapsed_sec(), critical_path.delay(), sTNS, sWNS, tot_iter); - if (placer_opts.place_algorithm.is_timing_driven() && placer_opts.place_agent_multistate && agent_state == EARLY_IN_THE_ANNEAL) { - if (state.alpha < 0.85 && state.alpha > 0.6) { - agent_state = LATE_IN_THE_ANNEAL; - VTR_LOG("Agent's 2nd state: \n"); - } - } - - sprintf(msg, "Cost: %g BB Cost %g TD Cost %g Temperature: %g", - costs.cost, costs.bb_cost, costs.timing_cost, state.t); - update_screen(ScreenUpdatePriority::MINOR, msg, PLACEMENT, timing_info); + //RL agent state definition + e_agent_state agent_state = EARLY_IN_THE_ANNEAL; + + std::unique_ptr current_move_generator; + + //Define the timing bb weight factor for the agent's reward function + float timing_bb_factor = REWARD_BB_TIMING_RELATIVE_WEIGHT; + + if (skip_anneal == false) { + //Table header + VTR_LOG("\n"); + print_place_status_header(); + + /* Outer loop of the simulated annealing begins */ + do { + vtr::Timer temperature_timer; + + outer_loop_update_timing_info(placer_opts, &costs, num_connections, + state.crit_exponent, &outer_crit_iter_count, + place_delay_model.get(), placer_criticalities.get(), + placer_setup_slacks.get(), pin_timing_invalidator.get(), + timing_info.get()); + + if (placer_opts.place_algorithm.is_timing_driven()) { + critical_path = timing_info->least_slack_critical_path(); + sTNS = timing_info->setup_total_negative_slack(); + sWNS = timing_info->setup_worst_negative_slack(); + + //see if we should save the current placement solution as a checkpoint + + if (placer_opts.place_checkpointing + && agent_state == LATE_IN_THE_ANNEAL) { + save_placement_checkpoint_if_needed(placement_checkpoint, + timing_info, costs, critical_path.delay()); + } + } + + //move the appropoiate move_generator to be the current used move generator + assign_current_move_generator(move_generator, move_generator2, + agent_state, placer_opts, false, current_move_generator); + + //do a complete inner loop iteration + placement_inner_loop(&state, placer_opts, inner_recompute_limit, + &stats, &costs, &moves_since_cost_recompute, + pin_timing_invalidator.get(), place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + *current_move_generator, *manual_move_generator, + blocks_affected, timing_info.get(), + placer_opts.place_algorithm, move_type_stat, + timing_bb_factor); + + //move the update used move_generator to its original variable + update_move_generator(move_generator, move_generator2, agent_state, + placer_opts, false, current_move_generator); + + tot_iter += state.move_lim; + ++state.num_temps; + + print_place_status(state, stats, temperature_timer.elapsed_sec(), + critical_path.delay(), sTNS, sWNS, tot_iter); + if (placer_opts.place_algorithm.is_timing_driven() + && placer_opts.place_agent_multistate + && agent_state == EARLY_IN_THE_ANNEAL) { + if (state.alpha < 0.85 && state.alpha > 0.6) { + agent_state = LATE_IN_THE_ANNEAL; + VTR_LOG("Agent's 2nd state: \n"); + } + } + + sprintf(msg, "Cost: %g BB Cost %g TD Cost %g Temperature: %g", + costs.cost, costs.bb_cost, costs.timing_cost, state.t); + update_screen(ScreenUpdatePriority::MINOR, msg, PLACEMENT, + timing_info); #ifdef VERBOSE if (getEchoEnabled()) { print_clb_placement("first_iteration_clb_placement.echo"); } #endif - } while (state.outer_loop_update(stats.success_rate, costs, placer_opts, annealing_sched)); - /* Outer loop of the simmulated annealing ends */ - } //skip_anneal ends - - /* Start Quench */ - state.t = 0; //Freeze out: only accept solutions that improve placement. - state.move_lim = state.move_lim_max; //Revert the move limit to initial value. - - auto pre_quench_timing_stats = timing_ctx.stats; - { /* Quench */ - - vtr::ScopedFinishTimer temperature_timer("Placement Quench"); - - outer_loop_update_timing_info(placer_opts, - &costs, - num_connections, - state.crit_exponent, - &outer_crit_iter_count, - place_delay_model.get(), - placer_criticalities.get(), - placer_setup_slacks.get(), - pin_timing_invalidator.get(), - timing_info.get()); - - //move the appropoiate move_generator to be the current used move generator - assign_current_move_generator(move_generator, move_generator2, agent_state, placer_opts, true, current_move_generator); - - /* Run inner loop again with temperature = 0 so as to accept only swaps - * which reduce the cost of the placement */ - placement_inner_loop(&state, placer_opts, - quench_recompute_limit, &stats, - &costs, - &moves_since_cost_recompute, - pin_timing_invalidator.get(), - place_delay_model.get(), - placer_criticalities.get(), - placer_setup_slacks.get(), - *current_move_generator, - *manual_move_generator, - blocks_affected, - timing_info.get(), - placer_opts.place_quench_algorithm, - move_type_stat, - timing_bb_factor); - - //move the update used move_generator to its original variable - update_move_generator(move_generator, move_generator2, agent_state, placer_opts, true, current_move_generator); - - tot_iter += state.move_lim; - ++state.num_temps; - - if (placer_opts.place_quench_algorithm.is_timing_driven()) { - critical_path = timing_info->least_slack_critical_path(); - sTNS = timing_info->setup_total_negative_slack(); - sWNS = timing_info->setup_worst_negative_slack(); - } - - print_place_status(state, stats, temperature_timer.elapsed_sec(), critical_path.delay(), sTNS, sWNS, tot_iter); - } - auto post_quench_timing_stats = timing_ctx.stats; - - //Final timing analysis - PlaceCritParams crit_params; - crit_params.crit_exponent = state.crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - if (placer_opts.place_algorithm.is_timing_driven()) { - perform_full_timing_update(crit_params, - place_delay_model.get(), - placer_criticalities.get(), - placer_setup_slacks.get(), - pin_timing_invalidator.get(), - timing_info.get(), - &costs); - VTR_LOG("post-quench CPD = %g (ns) \n", 1e9 * timing_info->least_slack_critical_path().delay()); - } - - //See if our latest checkpoint is better than the current placement solution - if (placer_opts.place_checkpointing) - restore_best_placement(placement_checkpoint, timing_info, costs, placer_criticalities, placer_setup_slacks, place_delay_model, pin_timing_invalidator, crit_params); - - if (placer_opts.placement_saves_per_temperature >= 1) { - std::string filename = vtr::string_fmt("placement_%03d_%03d.place", state.num_temps + 1, 0); - VTR_LOG("Saving final placement to file: %s\n", filename.c_str()); - print_place(nullptr, nullptr, filename.c_str()); - } - - // TODO: - // 1. add some subroutine hierarchy! Too big! + } while (state.outer_loop_update(stats.success_rate, costs, placer_opts, + annealing_sched)); + /* Outer loop of the simmulated annealing ends */ + } //skip_anneal ends + + /* Start Quench */ + state.t = 0; //Freeze out: only accept solutions that improve placement. + state.move_lim = state.move_lim_max; //Revert the move limit to initial value. + + auto pre_quench_timing_stats = timing_ctx.stats; + { /* Quench */ + + vtr::ScopedFinishTimer temperature_timer("Placement Quench"); + + outer_loop_update_timing_info(placer_opts, &costs, num_connections, + state.crit_exponent, &outer_crit_iter_count, + place_delay_model.get(), placer_criticalities.get(), + placer_setup_slacks.get(), pin_timing_invalidator.get(), + timing_info.get()); + + //move the appropoiate move_generator to be the current used move generator + assign_current_move_generator(move_generator, move_generator2, + agent_state, placer_opts, true, current_move_generator); + + /* Run inner loop again with temperature = 0 so as to accept only swaps + * which reduce the cost of the placement */ + placement_inner_loop(&state, placer_opts, quench_recompute_limit, + &stats, &costs, &moves_since_cost_recompute, + pin_timing_invalidator.get(), place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + *current_move_generator, *manual_move_generator, + blocks_affected, timing_info.get(), + placer_opts.place_quench_algorithm, move_type_stat, + timing_bb_factor); + + //move the update used move_generator to its original variable + update_move_generator(move_generator, move_generator2, agent_state, + placer_opts, true, current_move_generator); + + tot_iter += state.move_lim; + ++state.num_temps; + + if (placer_opts.place_quench_algorithm.is_timing_driven()) { + critical_path = timing_info->least_slack_critical_path(); + sTNS = timing_info->setup_total_negative_slack(); + sWNS = timing_info->setup_worst_negative_slack(); + } + + print_place_status(state, stats, temperature_timer.elapsed_sec(), + critical_path.delay(), sTNS, sWNS, tot_iter); + } + auto post_quench_timing_stats = timing_ctx.stats; + + //Final timing analysis + PlaceCritParams crit_params; + crit_params.crit_exponent = state.crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + if (placer_opts.place_algorithm.is_timing_driven()) { + perform_full_timing_update(crit_params, place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + pin_timing_invalidator.get(), timing_info.get(), &costs); + VTR_LOG("post-quench CPD = %g (ns) \n", + 1e9 * timing_info->least_slack_critical_path().delay()); + } + + //See if our latest checkpoint is better than the current placement solution + if (placer_opts.place_checkpointing) + restore_best_placement(placement_checkpoint, timing_info, costs, + placer_criticalities, placer_setup_slacks, place_delay_model, + pin_timing_invalidator, crit_params); + + if (placer_opts.placement_saves_per_temperature >= 1) { + std::string filename = vtr::string_fmt("placement_%03d_%03d.place", + state.num_temps + 1, 0); + VTR_LOG("Saving final placement to file: %s\n", filename.c_str()); + print_place(nullptr, nullptr, filename.c_str()); + } + + // TODO: + // 1. add some subroutine hierarchy! Too big! #ifdef VERBOSE if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_END_CLB_PLACEMENT)) { @@ -885,190 +878,167 @@ void try_place(const t_placer_opts& placer_opts, } #endif - check_place(costs, place_delay_model.get(), placer_criticalities.get(), placer_opts.place_algorithm); - - //Some stats - VTR_LOG("\n"); - VTR_LOG("Swaps called: %d\n", num_ts_called); - report_aborted_moves(); - - if (placer_opts.place_algorithm.is_timing_driven()) { - //Final timing estimate - VTR_ASSERT(timing_info); - - critical_path = timing_info->least_slack_critical_path(); - - if (isEchoFileEnabled(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH)) { - tatum::write_echo(getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH), - *timing_ctx.graph, *timing_ctx.constraints, *placement_delay_calc, timing_info->analyzer()); - - tatum::NodeId debug_tnode = id_or_pin_name_to_tnode(analysis_opts.echo_dot_timing_graph_node); - write_setup_timing_graph_dot(getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH) + std::string(".dot"), - *timing_info, debug_tnode); - } - - generate_post_place_timing_reports(placer_opts, - analysis_opts, - *timing_info, - *placement_delay_calc); - - /* Print critical path delay metrics */ - VTR_LOG("\n"); - print_setup_timing_summary(*timing_ctx.constraints, *timing_info->setup_analyzer(), "Placement estimated "); - } - - sprintf(msg, "Placement. Cost: %g bb_cost: %g td_cost: %g Channel Factor: %d", - costs.cost, costs.bb_cost, costs.timing_cost, width_fac); - VTR_LOG("Placement cost: %g, bb_cost: %g, td_cost: %g, \n", - costs.cost, costs.bb_cost, costs.timing_cost); - update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); - // Print out swap statistics - print_resources_utilization(); - - print_placement_swaps_stats(state); - - print_placement_move_types_stats(move_type_stat); - - free_placement_structs(placer_opts); - free_try_swap_arrays(); - - print_timing_stats("Placement Quench", post_quench_timing_stats, pre_quench_timing_stats); - print_timing_stats("Placement Total ", timing_ctx.stats, pre_place_timing_stats); - - VTR_LOG( - "update_td_costs: connections %g nets %g sum_nets %g total %g\n", - p_runtime_ctx.f_update_td_costs_connections_elapsed_sec, - p_runtime_ctx.f_update_td_costs_nets_elapsed_sec, - p_runtime_ctx.f_update_td_costs_sum_nets_elapsed_sec, - p_runtime_ctx.f_update_td_costs_total_elapsed_sec); + check_place(costs, place_delay_model.get(), placer_criticalities.get(), + placer_opts.place_algorithm); + + //Some stats + VTR_LOG("\n"); + VTR_LOG("Swaps called: %d\n", num_ts_called); + report_aborted_moves(); + + if (placer_opts.place_algorithm.is_timing_driven()) { + //Final timing estimate + VTR_ASSERT(timing_info); + + critical_path = timing_info->least_slack_critical_path(); + + if (isEchoFileEnabled(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH)) { + tatum::write_echo( + getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH), + *timing_ctx.graph, *timing_ctx.constraints, + *placement_delay_calc, timing_info->analyzer()); + + tatum::NodeId debug_tnode = id_or_pin_name_to_tnode( + analysis_opts.echo_dot_timing_graph_node); + write_setup_timing_graph_dot( + getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH) + + std::string(".dot"), *timing_info, debug_tnode); + } + + generate_post_place_timing_reports(placer_opts, analysis_opts, + *timing_info, *placement_delay_calc); + + /* Print critical path delay metrics */ + VTR_LOG("\n"); + print_setup_timing_summary(*timing_ctx.constraints, + *timing_info->setup_analyzer(), "Placement estimated "); + } + + sprintf(msg, + "Placement. Cost: %g bb_cost: %g td_cost: %g Channel Factor: %d", + costs.cost, costs.bb_cost, costs.timing_cost, width_fac); + VTR_LOG("Placement cost: %g, bb_cost: %g, td_cost: %g, \n", costs.cost, + costs.bb_cost, costs.timing_cost); + update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); + // Print out swap statistics + print_resources_utilization(); + + print_placement_swaps_stats(state); + + print_placement_move_types_stats(move_type_stat); + + free_placement_structs(placer_opts); + free_try_swap_arrays(); + + print_timing_stats("Placement Quench", post_quench_timing_stats, + pre_quench_timing_stats); + print_timing_stats("Placement Total ", timing_ctx.stats, + pre_place_timing_stats); + + VTR_LOG("update_td_costs: connections %g nets %g sum_nets %g total %g\n", + p_runtime_ctx.f_update_td_costs_connections_elapsed_sec, + p_runtime_ctx.f_update_td_costs_nets_elapsed_sec, + p_runtime_ctx.f_update_td_costs_sum_nets_elapsed_sec, + p_runtime_ctx.f_update_td_costs_total_elapsed_sec); } /* Function to update the setup slacks and criticalities before the inner loop of the annealing/quench */ -static void outer_loop_update_timing_info(const t_placer_opts& placer_opts, - t_placer_costs* costs, - int num_connections, - float crit_exponent, - int* outer_crit_iter_count, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - SetupTimingInfo* timing_info) { - if (!placer_opts.place_algorithm.is_timing_driven()) { - return; - } - - /*at each temperature change we update these values to be used */ - /*for normalizing the tradeoff between timing and wirelength (bb) */ - if (*outer_crit_iter_count >= placer_opts.recompute_crit_iter - || placer_opts.inner_loop_recompute_divider != 0) { +static void outer_loop_update_timing_info(const t_placer_opts &placer_opts, + t_placer_costs *costs, int num_connections, float crit_exponent, + int *outer_crit_iter_count, const PlaceDelayModel *delay_model, + PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + SetupTimingInfo *timing_info) { + if (!placer_opts.place_algorithm.is_timing_driven()) { + return; + } + + /*at each temperature change we update these values to be used */ + /*for normalizing the tradeoff between timing and wirelength (bb) */ + if (*outer_crit_iter_count >= placer_opts.recompute_crit_iter + || placer_opts.inner_loop_recompute_divider != 0) { #ifdef VERBOSE VTR_LOG("Outer loop recompute criticalities\n"); #endif - num_connections = std::max(num_connections, 1); //Avoid division by zero - VTR_ASSERT(num_connections > 0); - - PlaceCritParams crit_params; - crit_params.crit_exponent = crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - //Update all timing related classes - perform_full_timing_update(crit_params, - delay_model, - criticalities, - setup_slacks, - pin_timing_invalidator, - timing_info, - costs); - - *outer_crit_iter_count = 0; - } - (*outer_crit_iter_count)++; + num_connections = std::max(num_connections, 1); //Avoid division by zero + VTR_ASSERT(num_connections > 0); + + PlaceCritParams crit_params; + crit_params.crit_exponent = crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; - /* Update the cost normalization factors */ - costs->update_norm_factors(); + //Update all timing related classes + perform_full_timing_update(crit_params, delay_model, criticalities, + setup_slacks, pin_timing_invalidator, timing_info, costs); + + *outer_crit_iter_count = 0; + } + (*outer_crit_iter_count)++; + + /* Update the cost normalization factors */ + costs->update_norm_factors(); } /* Function which contains the inner loop of the simulated annealing */ -static void placement_inner_loop(const t_annealing_state* state, - const t_placer_opts& placer_opts, - int inner_recompute_limit, - t_placer_statistics* stats, - t_placer_costs* costs, - int* moves_since_cost_recompute, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - MoveGenerator& move_generator, - ManualMoveGenerator& manual_move_generator, - t_pl_blocks_to_be_moved& blocks_affected, - SetupTimingInfo* timing_info, - const t_place_algorithm& place_algorithm, - MoveTypeStat& move_type_stat, - float timing_bb_factor) { - int inner_crit_iter_count, inner_iter; - - int inner_placement_save_count = 0; //How many times have we dumped placement to a file this temperature? - - stats->reset(); - - inner_crit_iter_count = 1; - - /* Inner loop begins */ - for (inner_iter = 0; inner_iter < state->move_lim; inner_iter++) { - e_move_result swap_result = try_swap(state, - costs, - move_generator, - manual_move_generator, - timing_info, - pin_timing_invalidator, - blocks_affected, - delay_model, - criticalities, - setup_slacks, - placer_opts, - move_type_stat, - place_algorithm, - timing_bb_factor); - - if (swap_result == ACCEPTED) { - /* Move was accepted. Update statistics that are useful for the annealing schedule. */ - stats->single_swap_update(*costs); - num_swap_accepted++; - } else if (swap_result == ABORTED) { - num_swap_aborted++; - } else { // swap_result == REJECTED - num_swap_rejected++; - } - - if (place_algorithm.is_timing_driven()) { - /* Do we want to re-timing analyze the circuit to get updated slack and criticality values? - * We do this only once in a while, since it is expensive. - */ - if (inner_crit_iter_count >= inner_recompute_limit - && inner_iter != state->move_lim - 1) { /*on last iteration don't recompute */ - - inner_crit_iter_count = 0; +static void placement_inner_loop(const t_annealing_state *state, + const t_placer_opts &placer_opts, int inner_recompute_limit, + t_placer_statistics *stats, t_placer_costs *costs, + int *moves_since_cost_recompute, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, + PlacerSetupSlacks *setup_slacks, MoveGenerator &move_generator, + ManualMoveGenerator &manual_move_generator, + t_pl_blocks_to_be_moved &blocks_affected, SetupTimingInfo *timing_info, + const t_place_algorithm &place_algorithm, MoveTypeStat &move_type_stat, + float timing_bb_factor) { + int inner_crit_iter_count, inner_iter; + + int inner_placement_save_count = 0; //How many times have we dumped placement to a file this temperature? + + stats->reset(); + + inner_crit_iter_count = 1; + + /* Inner loop begins */ + for (inner_iter = 0; inner_iter < state->move_lim; inner_iter++) { + e_move_result swap_result = try_swap(state, costs, move_generator, + manual_move_generator, timing_info, pin_timing_invalidator, + blocks_affected, delay_model, criticalities, setup_slacks, + placer_opts, move_type_stat, place_algorithm, timing_bb_factor); + + if (swap_result == ACCEPTED) { + /* Move was accepted. Update statistics that are useful for the annealing schedule. */ + stats->single_swap_update(*costs); + num_swap_accepted++; + } else if (swap_result == ABORTED) { + num_swap_aborted++; + } else { // swap_result == REJECTED + num_swap_rejected++; + } + + if (place_algorithm.is_timing_driven()) { + /* Do we want to re-timing analyze the circuit to get updated slack and criticality values? + * We do this only once in a while, since it is expensive. + */ + if (inner_crit_iter_count >= inner_recompute_limit + && inner_iter != state->move_lim - 1) { /*on last iteration don't recompute */ + + inner_crit_iter_count = 0; #ifdef VERBOSE VTR_LOG("Inner loop recompute criticalities\n"); #endif - PlaceCritParams crit_params; - crit_params.crit_exponent = state->crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - //Update all timing related classes - perform_full_timing_update(crit_params, - delay_model, - criticalities, - setup_slacks, - pin_timing_invalidator, - timing_info, - costs); - } - inner_crit_iter_count++; - } + PlaceCritParams crit_params; + crit_params.crit_exponent = state->crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + //Update all timing related classes + perform_full_timing_update(crit_params, delay_model, + criticalities, setup_slacks, pin_timing_invalidator, + timing_info, costs); + } + inner_crit_iter_count++; + } #ifdef VERBOSE VTR_LOG("t = %g cost = %g bb_cost = %g timing_cost = %g move = %d\n", t, costs->cost, costs->bb_cost, costs->timing_cost, inner_iter); @@ -1077,180 +1047,181 @@ static void placement_inner_loop(const t_annealing_state* state, "fabs((*bb_cost) - comp_bb_cost(CHECK)) > (*bb_cost) * ERROR_TOL"); #endif - /* Lines below prevent too much round-off error from accumulating - * in the cost over many iterations (due to incremental updates). - * This round-off can lead to error checks failing because the cost - * is different from what you get when you recompute from scratch. - */ - ++(*moves_since_cost_recompute); - if (*moves_since_cost_recompute > MAX_MOVES_BEFORE_RECOMPUTE) { - recompute_costs_from_scratch(placer_opts, delay_model, criticalities, costs); - *moves_since_cost_recompute = 0; - } - - if (placer_opts.placement_saves_per_temperature >= 1 - && inner_iter > 0 - && (inner_iter + 1) % (state->move_lim / placer_opts.placement_saves_per_temperature) == 0) { - std::string filename = vtr::string_fmt("placement_%03d_%03d.place", state->num_temps + 1, inner_placement_save_count); - VTR_LOG("Saving placement to file at temperature move %d / %d: %s\n", inner_iter, state->move_lim, filename.c_str()); - print_place(nullptr, nullptr, filename.c_str()); - ++inner_placement_save_count; - } - } - - /* Calculate the success_rate and std_dev of the costs. */ - stats->calc_iteration_stats(*costs, state->move_lim); + /* Lines below prevent too much round-off error from accumulating + * in the cost over many iterations (due to incremental updates). + * This round-off can lead to error checks failing because the cost + * is different from what you get when you recompute from scratch. + */ + ++(*moves_since_cost_recompute); + if (*moves_since_cost_recompute > MAX_MOVES_BEFORE_RECOMPUTE) { + recompute_costs_from_scratch(placer_opts, delay_model, + criticalities, costs); + *moves_since_cost_recompute = 0; + } + + if (placer_opts.placement_saves_per_temperature >= 1 && inner_iter > 0 + && (inner_iter + 1) + % (state->move_lim + / placer_opts.placement_saves_per_temperature) + == 0) { + std::string filename = vtr::string_fmt("placement_%03d_%03d.place", + state->num_temps + 1, inner_placement_save_count); + VTR_LOG( + "Saving placement to file at temperature move %d / %d: %s\n", + inner_iter, state->move_lim, filename.c_str()); + print_place(nullptr, nullptr, filename.c_str()); + ++inner_placement_save_count; + } + } + + /* Calculate the success_rate and std_dev of the costs. */ + stats->calc_iteration_stats(*costs, state->move_lim); } -static void recompute_costs_from_scratch(const t_placer_opts& placer_opts, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - t_placer_costs* costs) { - double new_bb_cost = recompute_bb_cost(); - if (fabs(new_bb_cost - costs->bb_cost) > costs->bb_cost * ERROR_TOL) { - std::string msg = vtr::string_fmt("in recompute_costs_from_scratch: new_bb_cost = %g, old bb_cost = %g\n", - new_bb_cost, costs->bb_cost); - VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); - } - costs->bb_cost = new_bb_cost; - - if (placer_opts.place_algorithm.is_timing_driven()) { - double new_timing_cost = 0.; - comp_td_costs(delay_model, *criticalities, &new_timing_cost); - if (fabs(new_timing_cost - costs->timing_cost) > costs->timing_cost * ERROR_TOL) { - std::string msg = vtr::string_fmt("in recompute_costs_from_scratch: new_timing_cost = %g, old timing_cost = %g, ERROR_TOL = %g\n", - new_timing_cost, costs->timing_cost, ERROR_TOL); - VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); - } - costs->timing_cost = new_timing_cost; - } else { - VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); - - costs->cost = new_bb_cost; - } +static void recompute_costs_from_scratch(const t_placer_opts &placer_opts, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, t_placer_costs *costs) { + double new_bb_cost = recompute_bb_cost(); + if (fabs(new_bb_cost - costs->bb_cost) > costs->bb_cost * ERROR_TOL) { + std::string msg = + vtr::string_fmt( + "in recompute_costs_from_scratch: new_bb_cost = %g, old bb_cost = %g\n", + new_bb_cost, costs->bb_cost); + VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); + } + costs->bb_cost = new_bb_cost; + + if (placer_opts.place_algorithm.is_timing_driven()) { + double new_timing_cost = 0.; + comp_td_costs(delay_model, *criticalities, &new_timing_cost); + if (fabs( + new_timing_cost + - costs->timing_cost) > costs->timing_cost * ERROR_TOL) { + std::string msg = + vtr::string_fmt( + "in recompute_costs_from_scratch: new_timing_cost = %g, old timing_cost = %g, ERROR_TOL = %g\n", + new_timing_cost, costs->timing_cost, ERROR_TOL); + VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); + } + costs->timing_cost = new_timing_cost; + } else { + VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); + + costs->cost = new_bb_cost; + } } /*only count non-global connections */ static int count_connections() { - int count = 0; + int count = 0; - auto& cluster_ctx = g_vpr_ctx.clustering(); - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) - continue; + auto &cluster_ctx = g_vpr_ctx.clustering(); + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + continue; - count += cluster_ctx.clb_nlist.net_sinks(net_id).size(); - } + count += cluster_ctx.clb_nlist.net_sinks(net_id).size(); + } - return (count); + return (count); } ///@brief Find the starting temperature for the annealing loop. -static float starting_t(const t_annealing_state* state, - t_placer_costs* costs, - t_annealing_sched annealing_sched, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - SetupTimingInfo* timing_info, - MoveGenerator& move_generator, - ManualMoveGenerator& manual_move_generator, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - t_pl_blocks_to_be_moved& blocks_affected, - const t_placer_opts& placer_opts, - MoveTypeStat& move_type_stat) { - if (annealing_sched.type == USER_SCHED) { - return (annealing_sched.init_t); - } - - auto& cluster_ctx = g_vpr_ctx.clustering(); - - /* Use to calculate the average of cost when swap is accepted. */ - int num_accepted = 0; - - /* Use double types to avoid round off. */ - double av = 0., sum_of_squares = 0.; - - /* Determines the block swap loop count. */ - int move_lim = std::min(state->move_lim_max, (int)cluster_ctx.clb_nlist.blocks().size()); - - for (int i = 0; i < move_lim; i++) { - //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack - e_move_result swap_result = try_swap(state, - costs, - move_generator, - manual_move_generator, - timing_info, - pin_timing_invalidator, - blocks_affected, - delay_model, - criticalities, - setup_slacks, - placer_opts, - move_type_stat, - placer_opts.place_algorithm, - REWARD_BB_TIMING_RELATIVE_WEIGHT); - - if (swap_result == ACCEPTED) { - num_accepted++; - av += costs->cost; - sum_of_squares += costs->cost * costs->cost; - num_swap_accepted++; - } else if (swap_result == ABORTED) { - num_swap_aborted++; - } else { - num_swap_rejected++; - } - } - - /* Take the average of the accepted swaps' cost values. */ - av = num_accepted > 0 ? (av / num_accepted) : 0.; - - /* Get the standard deviation. */ - double std_dev = get_std_dev(num_accepted, sum_of_squares, av); - - /* Print warning if not all swaps are accepted. */ - if (num_accepted != move_lim) { - VTR_LOG_WARN("Starting t: %d of %d configurations accepted.\n", num_accepted, move_lim); - } +static float starting_t(const t_annealing_state *state, t_placer_costs *costs, + t_annealing_sched annealing_sched, const PlaceDelayModel *delay_model, + PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, + SetupTimingInfo *timing_info, MoveGenerator &move_generator, + ManualMoveGenerator &manual_move_generator, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + t_pl_blocks_to_be_moved &blocks_affected, + const t_placer_opts &placer_opts, MoveTypeStat &move_type_stat) { + if (annealing_sched.type == USER_SCHED) { + return (annealing_sched.init_t); + } + + auto &cluster_ctx = g_vpr_ctx.clustering(); + + /* Use to calculate the average of cost when swap is accepted. */ + int num_accepted = 0; + + /* Use double types to avoid round off. */ + double av = 0., sum_of_squares = 0.; + + /* Determines the block swap loop count. */ + int move_lim = std::min(state->move_lim_max, + (int) cluster_ctx.clb_nlist.blocks().size()); + + for (int i = 0; i < move_lim; i++) { + //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack + e_move_result swap_result = try_swap(state, costs, move_generator, + manual_move_generator, timing_info, pin_timing_invalidator, + blocks_affected, delay_model, criticalities, setup_slacks, + placer_opts, move_type_stat, placer_opts.place_algorithm, + REWARD_BB_TIMING_RELATIVE_WEIGHT); + + if (swap_result == ACCEPTED) { + num_accepted++; + av += costs->cost; + sum_of_squares += costs->cost * costs->cost; + num_swap_accepted++; + } else if (swap_result == ABORTED) { + num_swap_aborted++; + } else { + num_swap_rejected++; + } + } + + /* Take the average of the accepted swaps' cost values. */ + av = num_accepted > 0 ? (av / num_accepted) : 0.; + + /* Get the standard deviation. */ + double std_dev = get_std_dev(num_accepted, sum_of_squares, av); + + /* Print warning if not all swaps are accepted. */ + if (num_accepted != move_lim) { + VTR_LOG_WARN("Starting t: %d of %d configurations accepted.\n", + num_accepted, move_lim); + } #ifdef VERBOSE /* Print stats related to finding the initital temp. */ VTR_LOG("std_dev: %g, average cost: %g, starting temp: %g\n", std_dev, av, 20. * std_dev); #endif - /* Set the initial temperature to 20 times the standard of deviation */ - /* so that the initial temperature adjusts according to the circuit */ - return (20. * std_dev); + /* Set the initial temperature to 20 times the standard of deviation */ + /* so that the initial temperature adjusts according to the circuit */ + return (20. * std_dev); } static void update_move_nets(int num_nets_affected) { - /* update net cost functions and reset flags. */ - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_move_ctx = g_placer_ctx.mutable_move(); + /* update net cost functions and reset flags. */ + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_move_ctx = g_placer_ctx.mutable_move(); - for (int inet_affected = 0; inet_affected < num_nets_affected; inet_affected++) { - ClusterNetId net_id = ts_nets_to_update[inet_affected]; + for (int inet_affected = 0; inet_affected < num_nets_affected; + inet_affected++) { + ClusterNetId net_id = ts_nets_to_update[inet_affected]; - place_move_ctx.bb_coords[net_id] = ts_bb_coord_new[net_id]; - if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET) - place_move_ctx.bb_num_on_edges[net_id] = ts_bb_edge_new[net_id]; + place_move_ctx.bb_coords[net_id] = ts_bb_coord_new[net_id]; + if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET) + place_move_ctx.bb_num_on_edges[net_id] = ts_bb_edge_new[net_id]; - net_cost[net_id] = proposed_net_cost[net_id]; + net_cost[net_id] = proposed_net_cost[net_id]; - /* negative proposed_net_cost value is acting as a flag. */ - proposed_net_cost[net_id] = -1; - bb_updated_before[net_id] = NOT_UPDATED_YET; - } + /* negative proposed_net_cost value is acting as a flag. */ + proposed_net_cost[net_id] = -1; + bb_updated_before[net_id] = NOT_UPDATED_YET; + } } static void reset_move_nets(int num_nets_affected) { - /* Reset the net cost function flags first. */ - for (int inet_affected = 0; inet_affected < num_nets_affected; inet_affected++) { - ClusterNetId net_id = ts_nets_to_update[inet_affected]; - proposed_net_cost[net_id] = -1; - bb_updated_before[net_id] = NOT_UPDATED_YET; - } + /* Reset the net cost function flags first. */ + for (int inet_affected = 0; inet_affected < num_nets_affected; + inet_affected++) { + ClusterNetId net_id = ts_nets_to_update[inet_affected]; + proposed_net_cost[net_id] = -1; + bb_updated_before[net_id] = NOT_UPDATED_YET; + } } /** @@ -1269,286 +1240,266 @@ static void reset_move_nets(int num_nets_affected) { * * @return Whether the block swap is accepted, rejected or aborted. */ -static e_move_result try_swap(const t_annealing_state* state, - t_placer_costs* costs, - MoveGenerator& move_generator, - ManualMoveGenerator& manual_move_generator, - SetupTimingInfo* timing_info, - ClusteredPinTimingInvalidator* pin_timing_invalidator, - t_pl_blocks_to_be_moved& blocks_affected, - const PlaceDelayModel* delay_model, - PlacerCriticalities* criticalities, - PlacerSetupSlacks* setup_slacks, - const t_placer_opts& placer_opts, - MoveTypeStat& move_type_stat, - const t_place_algorithm& place_algorithm, - float timing_bb_factor) { - /* Picks some block and moves it to another spot. If this spot is * - * occupied, switch the blocks. Assess the change in cost function. * - * rlim is the range limiter. * - * Returns whether the swap is accepted, rejected or aborted. * - * Passes back the new value of the cost functions. */ - - std::cout << "In the try swap function" << std::endl; - - float rlim_escape_fraction = placer_opts.rlim_escape_fraction; - float timing_tradeoff = placer_opts.timing_tradeoff; - - PlaceCritParams crit_params; - crit_params.crit_exponent = state->crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - e_move_type move_type; //move type number - - num_ts_called++; - - MoveOutcomeStats move_outcome_stats; - - /* I'm using negative values of proposed_net_cost as a flag, * - * so DO NOT use cost functions that can go negative. */ - - double delta_c = 0; //Change in cost due to this swap. - double bb_delta_c = 0; //Change in the bounding box (wiring) cost. - double timing_delta_c = 0; //Change in the timing cost (delay * criticality). - - /* Allow some fraction of moves to not be restricted by rlim, */ - /* in the hopes of better escaping local minima. */ - float rlim; - if (rlim_escape_fraction > 0. && vtr::frand() < rlim_escape_fraction) { - rlim = std::numeric_limits::infinity(); - } else { - rlim = state->rlim; - } +static e_move_result try_swap(const t_annealing_state *state, + t_placer_costs *costs, MoveGenerator &move_generator, + ManualMoveGenerator &manual_move_generator, + SetupTimingInfo *timing_info, + ClusteredPinTimingInvalidator *pin_timing_invalidator, + t_pl_blocks_to_be_moved &blocks_affected, + const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, + PlacerSetupSlacks *setup_slacks, const t_placer_opts &placer_opts, + MoveTypeStat &move_type_stat, const t_place_algorithm &place_algorithm, + float timing_bb_factor) { + /* Picks some block and moves it to another spot. If this spot is * + * occupied, switch the blocks. Assess the change in cost function. * + * rlim is the range limiter. * + * Returns whether the swap is accepted, rejected or aborted. * + * Passes back the new value of the cost functions. */ + + float rlim_escape_fraction = placer_opts.rlim_escape_fraction; + float timing_tradeoff = placer_opts.timing_tradeoff; + + PlaceCritParams crit_params; + crit_params.crit_exponent = state->crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + e_move_type move_type; //move type number + + num_ts_called++; + + MoveOutcomeStats move_outcome_stats; + + /* I'm using negative values of proposed_net_cost as a flag, * + * so DO NOT use cost functions that can go negative. */ + + double delta_c = 0; //Change in cost due to this swap. + double bb_delta_c = 0; //Change in the bounding box (wiring) cost. + double timing_delta_c = 0; //Change in the timing cost (delay * criticality). + + /* Allow some fraction of moves to not be restricted by rlim, */ + /* in the hopes of better escaping local minima. */ + float rlim; + if (rlim_escape_fraction > 0. && vtr::frand() < rlim_escape_fraction) { + rlim = std::numeric_limits::infinity(); + } else { + rlim = state->rlim; + } #ifndef NO_GRAPHICS - bool manual_move_flag = false; - manual_move_flag = get_manual_move_flag(); - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - - if(manual_move_flag) { - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - } - -#endif /* NO_GRAPHICS */ - - e_create_move create_move_outcome; + bool manual_move_flag = false; + manual_move_flag = get_manual_move_flag(); + ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - if(manual_move_flag) { - create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); - } - else { - //Generate a new move (perturbation) used to explore the space of possible placements - create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); - } - - ++move_type_stat.num_moves[(int)move_type]; - LOG_MOVE_STATS_PROPOSED(t, blocks_affected); - - e_move_result move_outcome = ABORTED; - - if (create_move_outcome == e_create_move::ABORT || (manual_move_flag && !manual_move_global->manual_move_info.valid_input)) { - LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN(), - "ABORTED", "illegal move"); - - move_outcome = ABORTED; - - ++move_type_stat.aborted_moves[(int)move_type]; - } else { - VTR_ASSERT(create_move_outcome == e_create_move::VALID); - - /* - * To make evaluating the move simpler (e.g. calculating changed bounding box), - * we first move the blocks to their new locations (apply the move to - * place_ctx.block_locs) and then compute the change in cost. If the move - * is accepted, the inverse look-up in place_ctx.grid_blocks is updated - * (committing the move). If the move is rejected, the blocks are returned to - * their original positions (reverting place_ctx.block_locs to its original state). - * - * Note that the inverse look-up place_ctx.grid_blocks is only updated after - * move acceptance is determined, so it should not be used when evaluating a move. - */ - - /* Update the block positions */ - apply_move_blocks(blocks_affected); - - //Find all the nets affected by this swap and update the wiring costs. - //This cost value doesn't depend on the timing info. - // - //Also find all the pins affected by the swap, and calculates new connection - //delays and timing costs and store them in proposed_* data structures. - int num_nets_affected = find_affected_nets_and_update_costs(place_algorithm, - delay_model, - criticalities, - blocks_affected, - bb_delta_c, - timing_delta_c); - - //For setup slack analysis, we first do a timing analysis to get the newest - //slack values resulted from the proposed block moves. If the move turns out - //to be accepted, we keep the updated slack values and commit the block moves. - //If rejected, we reject the proposed block moves and revert this timing analysis. - if (place_algorithm == SLACK_TIMING_PLACE) { - /* Invalidates timing of modified connections for incremental timing updates. */ - invalidate_affected_connections(blocks_affected, - pin_timing_invalidator, - timing_info); - - /* Update the connection_timing_cost and connection_delay * - * values from the temporary values. */ - commit_td_cost(blocks_affected); - - /* Update timing information. Since we are analyzing setup slacks, * - * we only update those values and keep the criticalities stale * - * so as not to interfere with the original timing driven algorithm. * - * - * Note: the timing info must be updated after applying block moves * - * and committing the timing driven delays and costs. * - * If we wish to revert this timing update due to move rejection, * - * we need to revert block moves and restore the timing values. */ - criticalities->disable_update(); - setup_slacks->enable_update(); - update_timing_classes(crit_params, - timing_info, - criticalities, - setup_slacks, - pin_timing_invalidator); - - /* Get the setup slack analysis cost */ - //TODO: calculate a weighted average of the slack cost and wiring cost - delta_c = analyze_setup_slack_cost(setup_slacks); - } else if (place_algorithm == CRITICALITY_TIMING_PLACE) { - /* Take delta_c as a combination of timing and wiring cost. In - * addition to `timing_tradeoff`, we normalize the cost values */ - delta_c = (1 - timing_tradeoff) * bb_delta_c * costs->bb_cost_norm - + timing_tradeoff * timing_delta_c * costs->timing_cost_norm; - } else { - VTR_ASSERT_SAFE(place_algorithm == BOUNDING_BOX_PLACE); - delta_c = bb_delta_c; - } - - /* 1 -> move accepted, 0 -> rejected. */ - move_outcome = assess_swap(delta_c, state->t); - - if(manual_move_flag && manual_move_global->manual_move_info.valid_input) { - - std::cout << "Manual move is valid" << std::endl; - manual_move_global->manual_move_info.delta_cost = delta_c; - manual_move_global->manual_move_info.delta_timing = timing_delta_c; - manual_move_global->manual_move_info.delta_bounding_box = bb_delta_c; - manual_move_global->manual_move_info.placer_move_outcome = move_outcome; - - cost_summary(); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - - std::cout << "After cost window summary" << std::endl; - move_outcome = manual_move_global->manual_move_info.user_move_outcome; - std::cout << "Move outcome after summary window: " << manual_move_global->manual_move_info.user_move_outcome << std::endl; - std::cout << "Move outcome after assigned: " << move_outcome << std::endl; - - /*//Highlighting the block in the new position. - ClusterBlockId clb_index = ClusterBlockId(manual_move_global->manual_move_info.blockID); - //Unselects all blocks first - deselect_all(); - //Highlight block in the new position requested by user - auto& cluster_ctx = g_vpr_ctx.clustering(); - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index);*/ - - - } - - if (move_outcome == ACCEPTED) { - costs->cost += delta_c; - costs->bb_cost += bb_delta_c; - - if (place_algorithm == SLACK_TIMING_PLACE) { - /* Update the timing driven cost as usual */ - costs->timing_cost += timing_delta_c; - - //Commit the setup slack information - //The timing delay and cost values should be committed already - commit_setup_slacks(setup_slacks); - } + if (manual_move_flag) { + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + } - if (place_algorithm == CRITICALITY_TIMING_PLACE) { - costs->timing_cost += timing_delta_c; - - /* Invalidates timing of modified connections for incremental * - * timing updates. These invalidations are accumulated for a * - * big timing update in the outer loop. */ - invalidate_affected_connections(blocks_affected, - pin_timing_invalidator, - timing_info); - - /* Update the connection_timing_cost and connection_delay * - * values from the temporary values. */ - commit_td_cost(blocks_affected); - } - - /* Update net cost functions and reset flags. */ - update_move_nets(num_nets_affected); - - /* Update clb data structures since we kept the move. */ - commit_move_blocks(blocks_affected); - - ++move_type_stat.accepted_moves[(int)move_type]; - } else { - VTR_ASSERT_SAFE(move_outcome == REJECTED); - - /* Reset the net cost function flags first. */ - reset_move_nets(num_nets_affected); - - /* Restore the place_ctx.block_locs data structures to their state before the move. */ - revert_move_blocks(blocks_affected); - - if (place_algorithm == SLACK_TIMING_PLACE) { - /* Revert the timing delays and costs to pre-update values. */ - /* These routines must be called after reverting the block moves. */ - //TODO: make this process incremental - comp_td_connection_delays(delay_model); - comp_td_costs(delay_model, *criticalities, &costs->timing_cost); - - /* Re-invalidate the affected sink pins since the proposed * - * move is rejected, and the same blocks are reverted to * - * their original positions. */ - invalidate_affected_connections(blocks_affected, - pin_timing_invalidator, - timing_info); - - /* Revert the timing update */ - update_timing_classes(crit_params, - timing_info, - criticalities, - setup_slacks, - pin_timing_invalidator); - - VTR_ASSERT_SAFE_MSG( - verify_connection_setup_slacks(setup_slacks), - "The current setup slacks should be identical to the values before the try swap timing info update."); - } - - if (place_algorithm == CRITICALITY_TIMING_PLACE) { - /* Unstage the values stored in proposed_* data structures */ - revert_td_cost(blocks_affected); - } - } - - move_outcome_stats.delta_cost_norm = delta_c; - move_outcome_stats.delta_bb_cost_norm = bb_delta_c * costs->bb_cost_norm; - move_outcome_stats.delta_timing_cost_norm = timing_delta_c * costs->timing_cost_norm; - - move_outcome_stats.delta_bb_cost_abs = bb_delta_c; - move_outcome_stats.delta_timing_cost_abs = timing_delta_c; - - LOG_MOVE_STATS_OUTCOME(delta_c, bb_delta_c, timing_delta_c, - (move_outcome ? "ACCEPTED" : "REJECTED"), ""); - } - move_outcome_stats.outcome = move_outcome; +#endif /* NO_GRAPHICS */ - calculate_reward_and_process_outcome(placer_opts, move_outcome_stats, delta_c, timing_bb_factor, move_generator); + e_create_move create_move_outcome; + + if (manual_move_flag) { + create_move_outcome = manual_move_generator.propose_move( + blocks_affected, rlim); + if (create_move_outcome == e_create_move::VALID) + std::cout << "Propose move: VALID" << std::endl; + else if (create_move_outcome == e_create_move::ABORT) + std::cout << "Propose move: ABORT" << std::endl; + } else { + //Generate a new move (perturbation) used to explore the space of possible placements + create_move_outcome = move_generator.propose_move(blocks_affected, + move_type, rlim, placer_opts, criticalities); + } + + ++move_type_stat.num_moves[(int) move_type]; + LOG_MOVE_STATS_PROPOSED(t, blocks_affected); + + e_move_result move_outcome = ABORTED; + + if (create_move_outcome == e_create_move::ABORT + || (manual_move_flag + && !manual_move_global->manual_move_info.valid_input)) { + LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), "ABORTED", + "illegal move"); + + move_outcome = ABORTED; + + ++move_type_stat.aborted_moves[(int) move_type]; + } else { + VTR_ASSERT(create_move_outcome == e_create_move::VALID); + + /* + * To make evaluating the move simpler (e.g. calculating changed bounding box), + * we first move the blocks to their new locations (apply the move to + * place_ctx.block_locs) and then compute the change in cost. If the move + * is accepted, the inverse look-up in place_ctx.grid_blocks is updated + * (committing the move). If the move is rejected, the blocks are returned to + * their original positions (reverting place_ctx.block_locs to its original state). + * + * Note that the inverse look-up place_ctx.grid_blocks is only updated after + * move acceptance is determined, so it should not be used when evaluating a move. + */ + + /* Update the block positions */ + apply_move_blocks(blocks_affected); + + //Find all the nets affected by this swap and update the wiring costs. + //This cost value doesn't depend on the timing info. + // + //Also find all the pins affected by the swap, and calculates new connection + //delays and timing costs and store them in proposed_* data structures. + int num_nets_affected = find_affected_nets_and_update_costs( + place_algorithm, delay_model, criticalities, blocks_affected, + bb_delta_c, timing_delta_c); + + //For setup slack analysis, we first do a timing analysis to get the newest + //slack values resulted from the proposed block moves. If the move turns out + //to be accepted, we keep the updated slack values and commit the block moves. + //If rejected, we reject the proposed block moves and revert this timing analysis. + if (place_algorithm == SLACK_TIMING_PLACE) { + /* Invalidates timing of modified connections for incremental timing updates. */ + invalidate_affected_connections(blocks_affected, + pin_timing_invalidator, timing_info); + + /* Update the connection_timing_cost and connection_delay * + * values from the temporary values. */ + commit_td_cost(blocks_affected); + + /* Update timing information. Since we are analyzing setup slacks, * + * we only update those values and keep the criticalities stale * + * so as not to interfere with the original timing driven algorithm. * + * + * Note: the timing info must be updated after applying block moves * + * and committing the timing driven delays and costs. * + * If we wish to revert this timing update due to move rejection, * + * we need to revert block moves and restore the timing values. */ + criticalities->disable_update(); + setup_slacks->enable_update(); + update_timing_classes(crit_params, timing_info, criticalities, + setup_slacks, pin_timing_invalidator); + + /* Get the setup slack analysis cost */ + //TODO: calculate a weighted average of the slack cost and wiring cost + delta_c = analyze_setup_slack_cost(setup_slacks); + } else if (place_algorithm == CRITICALITY_TIMING_PLACE) { + /* Take delta_c as a combination of timing and wiring cost. In + * addition to `timing_tradeoff`, we normalize the cost values */ + delta_c = (1 - timing_tradeoff) * bb_delta_c * costs->bb_cost_norm + + timing_tradeoff * timing_delta_c + * costs->timing_cost_norm; + } else { + VTR_ASSERT_SAFE(place_algorithm == BOUNDING_BOX_PLACE); + delta_c = bb_delta_c; + } + + /* 1 -> move accepted, 0 -> rejected. */ + move_outcome = assess_swap(delta_c, state->t); + + if (manual_move_flag && manual_move_global->manual_move_info.valid_input) { + update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); + cost_summary_dialog(); + + //User accepts or rejects the move. + move_outcome = manual_move_global->manual_move_info.user_move_outcome; + } + + if (move_outcome == ACCEPTED) { + costs->cost += delta_c; + costs->bb_cost += bb_delta_c; + + if (place_algorithm == SLACK_TIMING_PLACE) { + /* Update the timing driven cost as usual */ + costs->timing_cost += timing_delta_c; + + //Commit the setup slack information + //The timing delay and cost values should be committed already + commit_setup_slacks(setup_slacks); + } + + if (place_algorithm == CRITICALITY_TIMING_PLACE) { + costs->timing_cost += timing_delta_c; + + /* Invalidates timing of modified connections for incremental * + * timing updates. These invalidations are accumulated for a * + * big timing update in the outer loop. */ + invalidate_affected_connections(blocks_affected, + pin_timing_invalidator, timing_info); + + /* Update the connection_timing_cost and connection_delay * + * values from the temporary values. */ + commit_td_cost(blocks_affected); + } + + /* Update net cost functions and reset flags. */ + update_move_nets(num_nets_affected); + + /* Update clb data structures since we kept the move. */ + commit_move_blocks(blocks_affected); + + ++move_type_stat.accepted_moves[(int) move_type]; + + //Highlights the new block when manual move is selected. + if (manual_move_flag) { + highlight_block_location(); + } + + } else { + VTR_ASSERT_SAFE(move_outcome == REJECTED); + + /* Reset the net cost function flags first. */ + reset_move_nets(num_nets_affected); + + /* Restore the place_ctx.block_locs data structures to their state before the move. */ + revert_move_blocks(blocks_affected); + + if (place_algorithm == SLACK_TIMING_PLACE) { + /* Revert the timing delays and costs to pre-update values. */ + /* These routines must be called after reverting the block moves. */ + //TODO: make this process incremental + comp_td_connection_delays(delay_model); + comp_td_costs(delay_model, *criticalities, &costs->timing_cost); + + /* Re-invalidate the affected sink pins since the proposed * + * move is rejected, and the same blocks are reverted to * + * their original positions. */ + invalidate_affected_connections(blocks_affected, + pin_timing_invalidator, timing_info); + + /* Revert the timing update */ + update_timing_classes(crit_params, timing_info, criticalities, + setup_slacks, pin_timing_invalidator); + + VTR_ASSERT_SAFE_MSG( + verify_connection_setup_slacks(setup_slacks), + "The current setup slacks should be identical to the values before the try swap timing info update."); + } + + if (place_algorithm == CRITICALITY_TIMING_PLACE) { + /* Unstage the values stored in proposed_* data structures */ + revert_td_cost(blocks_affected); + } + } + + move_outcome_stats.delta_cost_norm = delta_c; + move_outcome_stats.delta_bb_cost_norm = bb_delta_c + * costs->bb_cost_norm; + move_outcome_stats.delta_timing_cost_norm = timing_delta_c + * costs->timing_cost_norm; + + move_outcome_stats.delta_bb_cost_abs = bb_delta_c; + move_outcome_stats.delta_timing_cost_abs = timing_delta_c; + + LOG_MOVE_STATS_OUTCOME(delta_c, bb_delta_c, timing_delta_c, + (move_outcome ? "ACCEPTED" : "REJECTED"), ""); + } + move_outcome_stats.outcome = move_outcome; + + calculate_reward_and_process_outcome(placer_opts, move_outcome_stats, + delta_c, timing_bb_factor, move_generator); #ifdef VTR_ENABLE_DEBUG_LOGGING # ifndef NO_GRAPHICS @@ -1556,16 +1507,20 @@ static e_move_result try_swap(const t_annealing_state* state, # endif #endif - /* Clear the data structure containing block move info */ - clear_move_blocks(blocks_affected); + /* Clear the data structure containing block move info */ + clear_move_blocks(blocks_affected); - //VTR_ASSERT(check_macro_placement_consistency() == 0); + //VTR_ASSERT(check_macro_placement_consistency() == 0); #if 0 //Check that each accepted swap yields a valid placement check_place(*costs, delay_model, place_algorithm); #endif - return move_outcome; + if (manual_move_flag) { + manual_move_global->manual_move_info.valid_input = true; + } + + return move_outcome; } /** @@ -1590,68 +1545,73 @@ static e_move_result try_swap(const t_annealing_state* state, * * @return The number of affected nets. */ -static int find_affected_nets_and_update_costs(const t_place_algorithm& place_algorithm, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - t_pl_blocks_to_be_moved& blocks_affected, - double& bb_delta_c, - double& timing_delta_c) { - VTR_ASSERT_SAFE(bb_delta_c == 0.); - VTR_ASSERT_SAFE(timing_delta_c == 0.); - auto& cluster_ctx = g_vpr_ctx.clustering(); - - int num_affected_nets = 0; - - /* Go through all the blocks moved. */ - for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { - ClusterBlockId blk = blocks_affected.moved_blocks[iblk].block_num; - - /* Go through all the pins in the moved block. */ - for (ClusterPinId blk_pin : cluster_ctx.clb_nlist.block_pins(blk)) { - ClusterNetId net_id = cluster_ctx.clb_nlist.pin_net(blk_pin); - VTR_ASSERT_SAFE_MSG(net_id, "Only valid nets should be found in compressed netlist block pins"); - - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) - //TODO: Do we require anyting special here for global nets? - //"Global nets are assumed to span the whole chip, and do not effect costs." - continue; - - /* Record effected nets */ - record_affected_net(net_id, num_affected_nets); - - /* Update the net bounding boxes. */ - update_net_bb(net_id, blocks_affected, iblk, blk, blk_pin); - - if (place_algorithm.is_timing_driven()) { - /* Determine the change in connection delay and timing cost. */ - update_td_delta_costs(delay_model, *criticalities, net_id, blk_pin, blocks_affected, timing_delta_c); - } - } - } - - /* Now update the bounding box costs (since the net bounding * - * boxes are up-to-date). The cost is only updated once per net. */ - for (int inet_affected = 0; inet_affected < num_affected_nets; inet_affected++) { - ClusterNetId net_id = ts_nets_to_update[inet_affected]; - - proposed_net_cost[net_id] = get_net_cost(net_id, &ts_bb_coord_new[net_id]); - bb_delta_c += proposed_net_cost[net_id] - net_cost[net_id]; - } - - return num_affected_nets; +static int find_affected_nets_and_update_costs( + const t_place_algorithm &place_algorithm, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, + t_pl_blocks_to_be_moved &blocks_affected, double &bb_delta_c, + double &timing_delta_c) { + VTR_ASSERT_SAFE(bb_delta_c == 0.); + VTR_ASSERT_SAFE(timing_delta_c == 0.); + auto &cluster_ctx = g_vpr_ctx.clustering(); + + int num_affected_nets = 0; + + /* Go through all the blocks moved. */ + for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { + ClusterBlockId blk = blocks_affected.moved_blocks[iblk].block_num; + + /* Go through all the pins in the moved block. */ + for (ClusterPinId blk_pin : cluster_ctx.clb_nlist.block_pins(blk)) { + ClusterNetId net_id = cluster_ctx.clb_nlist.pin_net(blk_pin); + VTR_ASSERT_SAFE_MSG(net_id, + "Only valid nets should be found in compressed netlist block pins"); + + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + //TODO: Do we require anyting special here for global nets? + //"Global nets are assumed to span the whole chip, and do not effect costs." + continue; + + /* Record effected nets */ + record_affected_net(net_id, num_affected_nets); + + /* Update the net bounding boxes. */ + update_net_bb(net_id, blocks_affected, iblk, blk, blk_pin); + + if (place_algorithm.is_timing_driven()) { + /* Determine the change in connection delay and timing cost. */ + update_td_delta_costs(delay_model, *criticalities, net_id, + blk_pin, blocks_affected, timing_delta_c); + } + } + } + + /* Now update the bounding box costs (since the net bounding * + * boxes are up-to-date). The cost is only updated once per net. */ + for (int inet_affected = 0; inet_affected < num_affected_nets; + inet_affected++) { + ClusterNetId net_id = ts_nets_to_update[inet_affected]; + + proposed_net_cost[net_id] = get_net_cost(net_id, + &ts_bb_coord_new[net_id]); + bb_delta_c += proposed_net_cost[net_id] - net_cost[net_id]; + } + + return num_affected_nets; } ///@brief Record effected nets. -static void record_affected_net(const ClusterNetId net, int& num_affected_nets) { - /* Record effected nets. */ - if (proposed_net_cost[net] < 0.) { - /* Net not marked yet. */ - ts_nets_to_update[num_affected_nets] = net; - num_affected_nets++; - - /* Flag to say we've marked this net. */ - proposed_net_cost[net] = 1.; - } +static void record_affected_net(const ClusterNetId net, + int &num_affected_nets) { + /* Record effected nets. */ + if (proposed_net_cost[net] < 0.) { + /* Net not marked yet. */ + ts_nets_to_update[num_affected_nets] = net; + num_affected_nets++; + + /* Flag to say we've marked this net. */ + proposed_net_cost[net] = 1.; + } } /** @@ -1661,34 +1621,33 @@ static void record_affected_net(const ClusterNetId net, int& num_affected_nets) * be updated once per net, not once per pin. */ static void update_net_bb(const ClusterNetId net, - const t_pl_blocks_to_be_moved& blocks_affected, - int iblk, - const ClusterBlockId blk, - const ClusterPinId blk_pin) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - - if (cluster_ctx.clb_nlist.net_sinks(net).size() < SMALL_NET) { - //For small nets brute-force bounding box update is faster - - if (bb_updated_before[net] == NOT_UPDATED_YET) { //Only once per-net - get_non_updateable_bb(net, &ts_bb_coord_new[net]); - } - } else { - //For large nets, update bounding box incrementally - int iblk_pin = tile_pin_index(blk_pin); - - t_physical_tile_type_ptr blk_type = physical_tile_type(blk); - int pin_width_offset = blk_type->pin_width_offset[iblk_pin]; - int pin_height_offset = blk_type->pin_height_offset[iblk_pin]; - - //Incremental bounding box update - update_bb(net, &ts_bb_coord_new[net], - &ts_bb_edge_new[net], - blocks_affected.moved_blocks[iblk].old_loc.x + pin_width_offset, - blocks_affected.moved_blocks[iblk].old_loc.y + pin_height_offset, - blocks_affected.moved_blocks[iblk].new_loc.x + pin_width_offset, - blocks_affected.moved_blocks[iblk].new_loc.y + pin_height_offset); - } + const t_pl_blocks_to_be_moved &blocks_affected, int iblk, + const ClusterBlockId blk, const ClusterPinId blk_pin) { + auto &cluster_ctx = g_vpr_ctx.clustering(); + + if (cluster_ctx.clb_nlist.net_sinks(net).size() < SMALL_NET) { + //For small nets brute-force bounding box update is faster + + if (bb_updated_before[net] == NOT_UPDATED_YET) { //Only once per-net + get_non_updateable_bb(net, &ts_bb_coord_new[net]); + } + } else { + //For large nets, update bounding box incrementally + int iblk_pin = tile_pin_index(blk_pin); + + t_physical_tile_type_ptr blk_type = physical_tile_type(blk); + int pin_width_offset = blk_type->pin_width_offset[iblk_pin]; + int pin_height_offset = blk_type->pin_height_offset[iblk_pin]; + + //Incremental bounding box update + update_bb(net, &ts_bb_coord_new[net], &ts_bb_edge_new[net], + blocks_affected.moved_blocks[iblk].old_loc.x + pin_width_offset, + blocks_affected.moved_blocks[iblk].old_loc.y + + pin_height_offset, + blocks_affected.moved_blocks[iblk].new_loc.x + pin_width_offset, + blocks_affected.moved_blocks[iblk].new_loc.y + + pin_height_offset); + } } /** @@ -1720,64 +1679,72 @@ static void update_net_bb(const ClusterNetId net, * This is also done to minimize the number of timing node/edge invalidations * for incremental static timing analysis (incremental STA). */ -static void update_td_delta_costs(const PlaceDelayModel* delay_model, - const PlacerCriticalities& criticalities, - const ClusterNetId net, - const ClusterPinId pin, - t_pl_blocks_to_be_moved& blocks_affected, - double& delta_timing_cost) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - - const auto& connection_delay = g_placer_ctx.timing().connection_delay; - auto& connection_timing_cost = g_placer_ctx.mutable_timing().connection_timing_cost; - auto& proposed_connection_delay = g_placer_ctx.mutable_timing().proposed_connection_delay; - auto& proposed_connection_timing_cost = g_placer_ctx.mutable_timing().proposed_connection_timing_cost; - - if (cluster_ctx.clb_nlist.pin_type(pin) == PinType::DRIVER) { - /* This pin is a net driver on a moved block. */ - /* Recompute all point to point connection delays for the net sinks. */ - for (size_t ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net).size(); ipin++) { - float temp_delay = comp_td_single_connection_delay(delay_model, net, ipin); - /* If the delay hasn't changed, do not mark this pin as affected */ - if (temp_delay == connection_delay[net][ipin]) { - continue; - } - - /* Calculate proposed delay and cost values */ - proposed_connection_delay[net][ipin] = temp_delay; - - proposed_connection_timing_cost[net][ipin] = criticalities.criticality(net, ipin) * temp_delay; - delta_timing_cost += proposed_connection_timing_cost[net][ipin] - connection_timing_cost[net][ipin]; - - /* Record this connection in blocks_affected.affected_pins */ - ClusterPinId sink_pin = cluster_ctx.clb_nlist.net_pin(net, ipin); - blocks_affected.affected_pins.push_back(sink_pin); - } - } else { - /* This pin is a net sink on a moved block */ - VTR_ASSERT_SAFE(cluster_ctx.clb_nlist.pin_type(pin) == PinType::SINK); - - /* Check if this sink's net is driven by a moved block */ - if (!driven_by_moved_block(net, blocks_affected)) { - /* Get the sink pin index in the net */ - int ipin = cluster_ctx.clb_nlist.pin_net_index(pin); - - float temp_delay = comp_td_single_connection_delay(delay_model, net, ipin); - /* If the delay hasn't changed, do not mark this pin as affected */ - if (temp_delay == connection_delay[net][ipin]) { - return; - } - - /* Calculate proposed delay and cost values */ - proposed_connection_delay[net][ipin] = temp_delay; - - proposed_connection_timing_cost[net][ipin] = criticalities.criticality(net, ipin) * temp_delay; - delta_timing_cost += proposed_connection_timing_cost[net][ipin] - connection_timing_cost[net][ipin]; - - /* Record this connection in blocks_affected.affected_pins */ - blocks_affected.affected_pins.push_back(pin); - } - } +static void update_td_delta_costs(const PlaceDelayModel *delay_model, + const PlacerCriticalities &criticalities, const ClusterNetId net, + const ClusterPinId pin, t_pl_blocks_to_be_moved &blocks_affected, + double &delta_timing_cost) { + auto &cluster_ctx = g_vpr_ctx.clustering(); + + const auto &connection_delay = g_placer_ctx.timing().connection_delay; + auto &connection_timing_cost = + g_placer_ctx.mutable_timing().connection_timing_cost; + auto &proposed_connection_delay = + g_placer_ctx.mutable_timing().proposed_connection_delay; + auto &proposed_connection_timing_cost = + g_placer_ctx.mutable_timing().proposed_connection_timing_cost; + + if (cluster_ctx.clb_nlist.pin_type(pin) == PinType::DRIVER) { + /* This pin is a net driver on a moved block. */ + /* Recompute all point to point connection delays for the net sinks. */ + for (size_t ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net).size(); + ipin++) { + float temp_delay = comp_td_single_connection_delay(delay_model, net, + ipin); + /* If the delay hasn't changed, do not mark this pin as affected */ + if (temp_delay == connection_delay[net][ipin]) { + continue; + } + + /* Calculate proposed delay and cost values */ + proposed_connection_delay[net][ipin] = temp_delay; + + proposed_connection_timing_cost[net][ipin] = + criticalities.criticality(net, ipin) * temp_delay; + delta_timing_cost += proposed_connection_timing_cost[net][ipin] + - connection_timing_cost[net][ipin]; + + /* Record this connection in blocks_affected.affected_pins */ + ClusterPinId sink_pin = cluster_ctx.clb_nlist.net_pin(net, ipin); + blocks_affected.affected_pins.push_back(sink_pin); + } + } else { + /* This pin is a net sink on a moved block */ + VTR_ASSERT_SAFE(cluster_ctx.clb_nlist.pin_type(pin) == PinType::SINK); + + /* Check if this sink's net is driven by a moved block */ + if (!driven_by_moved_block(net, blocks_affected)) { + /* Get the sink pin index in the net */ + int ipin = cluster_ctx.clb_nlist.pin_net_index(pin); + + float temp_delay = comp_td_single_connection_delay(delay_model, net, + ipin); + /* If the delay hasn't changed, do not mark this pin as affected */ + if (temp_delay == connection_delay[net][ipin]) { + return; + } + + /* Calculate proposed delay and cost values */ + proposed_connection_delay[net][ipin] = temp_delay; + + proposed_connection_timing_cost[net][ipin] = + criticalities.criticality(net, ipin) * temp_delay; + delta_timing_cost += proposed_connection_timing_cost[net][ipin] + - connection_timing_cost[net][ipin]; + + /* Record this connection in blocks_affected.affected_pins */ + blocks_affected.affected_pins.push_back(pin); + } + } } /** @@ -1798,80 +1765,82 @@ static void update_td_delta_costs(const PlaceDelayModel* delay_model, * value suddenly got very good due to the block move, while a good slack value * got very bad, perhaps even worse than the original worse slack value. */ -static float analyze_setup_slack_cost(const PlacerSetupSlacks* setup_slacks) { - const auto& cluster_ctx = g_vpr_ctx.clustering(); - const auto& clb_nlist = cluster_ctx.clb_nlist; - - const auto& p_timing_ctx = g_placer_ctx.timing(); - const auto& connection_setup_slack = p_timing_ctx.connection_setup_slack; - - //Find the original/proposed setup slacks of pins with modified values - std::vector original_setup_slacks, proposed_setup_slacks; - - auto clb_pins_modified = setup_slacks->pins_with_modified_setup_slack(); - for (ClusterPinId clb_pin : clb_pins_modified) { - ClusterNetId net_id = clb_nlist.pin_net(clb_pin); - size_t ipin = clb_nlist.pin_net_index(clb_pin); - - original_setup_slacks.push_back(connection_setup_slack[net_id][ipin]); - proposed_setup_slacks.push_back(setup_slacks->setup_slack(net_id, ipin)); - } - - //Sort in ascending order, from the worse slack value to the best - std::sort(original_setup_slacks.begin(), original_setup_slacks.end()); - std::sort(proposed_setup_slacks.begin(), proposed_setup_slacks.end()); - - //Check the first pair of slack values that are different - //If found, return their difference - for (size_t idiff = 0; idiff < original_setup_slacks.size(); ++idiff) { - float slack_diff = original_setup_slacks[idiff] - proposed_setup_slacks[idiff]; - - if (slack_diff != 0) { - return slack_diff; - } - } - - //If all slack values are identical (or no modified slack values), - //reject this move by returning an arbitrary positive number as cost. - return 1; +static float analyze_setup_slack_cost(const PlacerSetupSlacks *setup_slacks) { + const auto &cluster_ctx = g_vpr_ctx.clustering(); + const auto &clb_nlist = cluster_ctx.clb_nlist; + + const auto &p_timing_ctx = g_placer_ctx.timing(); + const auto &connection_setup_slack = p_timing_ctx.connection_setup_slack; + + //Find the original/proposed setup slacks of pins with modified values + std::vector original_setup_slacks, proposed_setup_slacks; + + auto clb_pins_modified = setup_slacks->pins_with_modified_setup_slack(); + for (ClusterPinId clb_pin : clb_pins_modified) { + ClusterNetId net_id = clb_nlist.pin_net(clb_pin); + size_t ipin = clb_nlist.pin_net_index(clb_pin); + + original_setup_slacks.push_back(connection_setup_slack[net_id][ipin]); + proposed_setup_slacks.push_back( + setup_slacks->setup_slack(net_id, ipin)); + } + + //Sort in ascending order, from the worse slack value to the best + std::sort(original_setup_slacks.begin(), original_setup_slacks.end()); + std::sort(proposed_setup_slacks.begin(), proposed_setup_slacks.end()); + + //Check the first pair of slack values that are different + //If found, return their difference + for (size_t idiff = 0; idiff < original_setup_slacks.size(); ++idiff) { + float slack_diff = original_setup_slacks[idiff] + - proposed_setup_slacks[idiff]; + + if (slack_diff != 0) { + return slack_diff; + } + } + + //If all slack values are identical (or no modified slack values), + //reject this move by returning an arbitrary positive number as cost. + return 1; } static e_move_result assess_swap(double delta_c, double t) { - /* Returns: 1 -> move accepted, 0 -> rejected. */ - if (delta_c <= 0) { - return ACCEPTED; - } - - if (t == 0.) { - return REJECTED; - } - - float fnum = vtr::frand(); - float prob_fac = std::exp(-delta_c / t); - if (prob_fac > fnum) { - return ACCEPTED; - } - - return REJECTED; + /* Returns: 1 -> move accepted, 0 -> rejected. */ + if (delta_c <= 0) { + return ACCEPTED; + } + + if (t == 0.) { + return REJECTED; + } + + float fnum = vtr::frand(); + float prob_fac = std::exp(-delta_c / t); + if (prob_fac > fnum) { + return ACCEPTED; + } + + return REJECTED; } static double recompute_bb_cost() { - /* Recomputes the cost to eliminate roundoff that may have accrued. * - * This routine does as little work as possible to compute this new * - * cost. */ + /* Recomputes the cost to eliminate roundoff that may have accrued. * + * This routine does as little work as possible to compute this new * + * cost. */ - double cost = 0; + double cost = 0; - auto& cluster_ctx = g_vpr_ctx.clustering(); + auto &cluster_ctx = g_vpr_ctx.clustering(); - for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ - if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ - /* Bounding boxes don't have to be recomputed; they're correct. */ - cost += net_cost[net_id]; - } - } + for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ + if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ + /* Bounding boxes don't have to be recomputed; they're correct. */ + cost += net_cost[net_id]; + } + } - return (cost); + return (cost); } /** @@ -1881,34 +1850,37 @@ static double recompute_bb_cost() { * All the connections have already been gathered by blocks_affected.affected_pins * after running the routine find_affected_nets_and_update_costs() in try_swap(). */ -static void commit_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& clb_nlist = cluster_ctx.clb_nlist; - - auto& p_timing_ctx = g_placer_ctx.mutable_timing(); - auto& connection_delay = p_timing_ctx.connection_delay; - auto& proposed_connection_delay = p_timing_ctx.proposed_connection_delay; - auto& connection_timing_cost = p_timing_ctx.connection_timing_cost; - auto& proposed_connection_timing_cost = p_timing_ctx.proposed_connection_timing_cost; - - //Go through all the sink pins affected - for (ClusterPinId pin_id : blocks_affected.affected_pins) { - ClusterNetId net_id = clb_nlist.pin_net(pin_id); - int ipin = clb_nlist.pin_net_index(pin_id); - - //Commit the timing delay and cost values - connection_delay[net_id][ipin] = proposed_connection_delay[net_id][ipin]; - proposed_connection_delay[net_id][ipin] = INVALID_DELAY; - connection_timing_cost[net_id][ipin] = proposed_connection_timing_cost[net_id][ipin]; - proposed_connection_timing_cost[net_id][ipin] = INVALID_DELAY; - } +static void commit_td_cost(const t_pl_blocks_to_be_moved &blocks_affected) { + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &clb_nlist = cluster_ctx.clb_nlist; + + auto &p_timing_ctx = g_placer_ctx.mutable_timing(); + auto &connection_delay = p_timing_ctx.connection_delay; + auto &proposed_connection_delay = p_timing_ctx.proposed_connection_delay; + auto &connection_timing_cost = p_timing_ctx.connection_timing_cost; + auto &proposed_connection_timing_cost = + p_timing_ctx.proposed_connection_timing_cost; + + //Go through all the sink pins affected + for (ClusterPinId pin_id : blocks_affected.affected_pins) { + ClusterNetId net_id = clb_nlist.pin_net(pin_id); + int ipin = clb_nlist.pin_net_index(pin_id); + + //Commit the timing delay and cost values + connection_delay[net_id][ipin] = + proposed_connection_delay[net_id][ipin]; + proposed_connection_delay[net_id][ipin] = INVALID_DELAY; + connection_timing_cost[net_id][ipin] = + proposed_connection_timing_cost[net_id][ipin]; + proposed_connection_timing_cost[net_id][ipin] = INVALID_DELAY; + } } //Reverts modifications to proposed_connection_delay and proposed_connection_timing_cost based on //the move proposed in blocks_affected -static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { +static void revert_td_cost(const t_pl_blocks_to_be_moved &blocks_affected) { #ifndef VTR_ASSERT_SAFE_ENABLED - static_cast(blocks_affected); + static_cast(blocks_affected); #else //Invalidate temp delay & timing cost values to match sanity checks in //comp_td_connection_cost() @@ -1937,29 +1909,32 @@ static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { * Invalidate all the timing graph edges associated with these connections via * the ClusteredPinTimingInvalidator class. */ -static void invalidate_affected_connections(const t_pl_blocks_to_be_moved& blocks_affected, - ClusteredPinTimingInvalidator* pin_tedges_invalidator, - TimingInfo* timing_info) { - VTR_ASSERT_SAFE(timing_info); - VTR_ASSERT_SAFE(pin_tedges_invalidator); - - /* Invalidate timing graph edges affected by the move */ - for (ClusterPinId pin : blocks_affected.affected_pins) { - pin_tedges_invalidator->invalidate_connection(pin, timing_info); - } +static void invalidate_affected_connections( + const t_pl_blocks_to_be_moved &blocks_affected, + ClusteredPinTimingInvalidator *pin_tedges_invalidator, + TimingInfo *timing_info) { + VTR_ASSERT_SAFE(timing_info); + VTR_ASSERT_SAFE(pin_tedges_invalidator); + + /* Invalidate timing graph edges affected by the move */ + for (ClusterPinId pin : blocks_affected.affected_pins) { + pin_tedges_invalidator->invalidate_connection(pin, timing_info); + } } //Returns true if 'net' is driven by one of the blocks in 'blocks_affected' -static bool driven_by_moved_block(const ClusterNetId net, const t_pl_blocks_to_be_moved& blocks_affected) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - - ClusterBlockId net_driver_block = cluster_ctx.clb_nlist.net_driver_block(net); - for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { - if (net_driver_block == blocks_affected.moved_blocks[iblk].block_num) { - return true; - } - } - return false; +static bool driven_by_moved_block(const ClusterNetId net, + const t_pl_blocks_to_be_moved &blocks_affected) { + auto &cluster_ctx = g_vpr_ctx.clustering(); + + ClusterBlockId net_driver_block = cluster_ctx.clb_nlist.net_driver_block( + net); + for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { + if (net_driver_block == blocks_affected.moved_blocks[iblk].block_num) { + return true; + } + } + return false; } /* Finds the cost from scratch. Done only when the placement * @@ -1971,303 +1946,324 @@ static bool driven_by_moved_block(const ClusterNetId net, const t_pl_blocks_to_b * cost which can be used to check the correctness of the * * other routine. */ static double comp_bb_cost(e_cost_methods method) { - double cost = 0; - double expected_wirelength = 0.0; - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_move_ctx = g_placer_ctx.mutable_move(); - - for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ - if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ - /* Small nets don't use incremental updating on their bounding boxes, * - * so they can use a fast bounding box calculator. */ - if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET && method == NORMAL) { - get_bb_from_scratch(net_id, &place_move_ctx.bb_coords[net_id], - &place_move_ctx.bb_num_on_edges[net_id]); - } else { - get_non_updateable_bb(net_id, &place_move_ctx.bb_coords[net_id]); - } - - net_cost[net_id] = get_net_cost(net_id, &place_move_ctx.bb_coords[net_id]); - cost += net_cost[net_id]; - if (method == CHECK) - expected_wirelength += get_net_wirelength_estimate(net_id, &place_move_ctx.bb_coords[net_id]); - } - } - - if (method == CHECK) { - VTR_LOG("\n"); - VTR_LOG("BB estimate of min-dist (placement) wire length: %.0f\n", expected_wirelength); - } - return cost; + double cost = 0; + double expected_wirelength = 0.0; + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_move_ctx = g_placer_ctx.mutable_move(); + + for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ + if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ + /* Small nets don't use incremental updating on their bounding boxes, * + * so they can use a fast bounding box calculator. */ + if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET + && method == NORMAL) { + get_bb_from_scratch(net_id, &place_move_ctx.bb_coords[net_id], + &place_move_ctx.bb_num_on_edges[net_id]); + } else { + get_non_updateable_bb(net_id, + &place_move_ctx.bb_coords[net_id]); + } + + net_cost[net_id] = get_net_cost(net_id, + &place_move_ctx.bb_coords[net_id]); + cost += net_cost[net_id]; + if (method == CHECK) + expected_wirelength += get_net_wirelength_estimate(net_id, + &place_move_ctx.bb_coords[net_id]); + } + } + + if (method == CHECK) { + VTR_LOG("\n"); + VTR_LOG("BB estimate of min-dist (placement) wire length: %.0f\n", + expected_wirelength); + } + return cost; } /* Allocates the major structures needed only by the placer, primarily for * * computing costs quickly and such. */ static void alloc_and_load_placement_structs(float place_cost_exp, - const t_placer_opts& placer_opts, - t_direct_inf* directs, - int num_directs) { - int max_pins_per_clb; - unsigned int ipin; + const t_placer_opts &placer_opts, t_direct_inf *directs, + int num_directs) { + int max_pins_per_clb; + unsigned int ipin; - const auto& device_ctx = g_vpr_ctx.device(); - const auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.mutable_placement(); + const auto &device_ctx = g_vpr_ctx.device(); + const auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_ctx = g_vpr_ctx.mutable_placement(); - auto& p_timing_ctx = g_placer_ctx.mutable_timing(); - auto& place_move_ctx = g_placer_ctx.mutable_move(); + auto &p_timing_ctx = g_placer_ctx.mutable_timing(); + auto &place_move_ctx = g_placer_ctx.mutable_move(); - size_t num_nets = cluster_ctx.clb_nlist.nets().size(); + size_t num_nets = cluster_ctx.clb_nlist.nets().size(); - init_placement_context(); + init_placement_context(); - max_pins_per_clb = 0; - for (const auto& type : device_ctx.physical_tile_types) { - max_pins_per_clb = max(max_pins_per_clb, type.num_pins); - } + max_pins_per_clb = 0; + for (const auto &type : device_ctx.physical_tile_types) { + max_pins_per_clb = max(max_pins_per_clb, type.num_pins); + } - if (placer_opts.place_algorithm.is_timing_driven()) { - /* Allocate structures associated with timing driven placement */ - /* [0..cluster_ctx.clb_nlist.nets().size()-1][1..num_pins-1] */ + if (placer_opts.place_algorithm.is_timing_driven()) { + /* Allocate structures associated with timing driven placement */ + /* [0..cluster_ctx.clb_nlist.nets().size()-1][1..num_pins-1] */ - p_timing_ctx.connection_delay = make_net_pins_matrix(cluster_ctx.clb_nlist, 0.f); - p_timing_ctx.proposed_connection_delay = make_net_pins_matrix(cluster_ctx.clb_nlist, 0.f); + p_timing_ctx.connection_delay = make_net_pins_matrix( + cluster_ctx.clb_nlist, 0.f); + p_timing_ctx.proposed_connection_delay = make_net_pins_matrix( + cluster_ctx.clb_nlist, 0.f); - p_timing_ctx.connection_setup_slack = make_net_pins_matrix(cluster_ctx.clb_nlist, std::numeric_limits::infinity()); + p_timing_ctx.connection_setup_slack = make_net_pins_matrix( + cluster_ctx.clb_nlist, std::numeric_limits::infinity()); - p_timing_ctx.connection_timing_cost = PlacerTimingCosts(cluster_ctx.clb_nlist); - p_timing_ctx.proposed_connection_timing_cost = make_net_pins_matrix(cluster_ctx.clb_nlist, 0.); - p_timing_ctx.net_timing_cost.resize(num_nets, 0.); + p_timing_ctx.connection_timing_cost = PlacerTimingCosts( + cluster_ctx.clb_nlist); + p_timing_ctx.proposed_connection_timing_cost = make_net_pins_matrix< + double>(cluster_ctx.clb_nlist, 0.); + p_timing_ctx.net_timing_cost.resize(num_nets, 0.); - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - for (ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ipin++) { - p_timing_ctx.connection_delay[net_id][ipin] = 0; - p_timing_ctx.proposed_connection_delay[net_id][ipin] = INVALID_DELAY; + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + for (ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); + ipin++) { + p_timing_ctx.connection_delay[net_id][ipin] = 0; + p_timing_ctx.proposed_connection_delay[net_id][ipin] = + INVALID_DELAY; - p_timing_ctx.proposed_connection_timing_cost[net_id][ipin] = INVALID_DELAY; + p_timing_ctx.proposed_connection_timing_cost[net_id][ipin] = + INVALID_DELAY; - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) continue; + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + continue; - p_timing_ctx.connection_timing_cost[net_id][ipin] = INVALID_DELAY; - } - } - } + p_timing_ctx.connection_timing_cost[net_id][ipin] = + INVALID_DELAY; + } + } + } - net_cost.resize(num_nets, -1.); - proposed_net_cost.resize(num_nets, -1.); - place_move_ctx.bb_coords.resize(num_nets, t_bb()); - place_move_ctx.bb_num_on_edges.resize(num_nets, t_bb()); + net_cost.resize(num_nets, -1.); + proposed_net_cost.resize(num_nets, -1.); + place_move_ctx.bb_coords.resize(num_nets, t_bb()); + place_move_ctx.bb_num_on_edges.resize(num_nets, t_bb()); - /* Used to store costs for moves not yet made and to indicate when a net's * - * cost has been recomputed. proposed_net_cost[inet] < 0 means net's cost hasn't * - * been recomputed. */ - bb_updated_before.resize(num_nets, NOT_UPDATED_YET); + /* Used to store costs for moves not yet made and to indicate when a net's * + * cost has been recomputed. proposed_net_cost[inet] < 0 means net's cost hasn't * + * been recomputed. */ + bb_updated_before.resize(num_nets, NOT_UPDATED_YET); - alloc_and_load_for_fast_cost_update(place_cost_exp); + alloc_and_load_for_fast_cost_update(place_cost_exp); - alloc_and_load_try_swap_structs(); + alloc_and_load_try_swap_structs(); - place_ctx.pl_macros = alloc_and_load_placement_macros(directs, num_directs); + place_ctx.pl_macros = alloc_and_load_placement_macros(directs, num_directs); } /* Frees the major structures needed by the placer (and not needed * * elsewhere). */ -static void free_placement_structs(const t_placer_opts& placer_opts) { - auto& place_move_ctx = g_placer_ctx.mutable_move(); - - if (placer_opts.place_algorithm.is_timing_driven()) { - auto& p_timing_ctx = g_placer_ctx.mutable_timing(); - - vtr::release_memory(p_timing_ctx.connection_timing_cost); - vtr::release_memory(p_timing_ctx.connection_delay); - vtr::release_memory(p_timing_ctx.connection_setup_slack); - vtr::release_memory(p_timing_ctx.proposed_connection_timing_cost); - vtr::release_memory(p_timing_ctx.proposed_connection_delay); - vtr::release_memory(p_timing_ctx.net_timing_cost); - } +static void free_placement_structs(const t_placer_opts &placer_opts) { + auto &place_move_ctx = g_placer_ctx.mutable_move(); + + if (placer_opts.place_algorithm.is_timing_driven()) { + auto &p_timing_ctx = g_placer_ctx.mutable_timing(); - free_placement_macros_structs(); + vtr::release_memory(p_timing_ctx.connection_timing_cost); + vtr::release_memory(p_timing_ctx.connection_delay); + vtr::release_memory(p_timing_ctx.connection_setup_slack); + vtr::release_memory(p_timing_ctx.proposed_connection_timing_cost); + vtr::release_memory(p_timing_ctx.proposed_connection_delay); + vtr::release_memory(p_timing_ctx.net_timing_cost); + } - vtr::release_memory(net_cost); - vtr::release_memory(proposed_net_cost); - vtr::release_memory(place_move_ctx.bb_coords); - vtr::release_memory(place_move_ctx.bb_num_on_edges); + free_placement_macros_structs(); - vtr::release_memory(bb_updated_before); + vtr::release_memory(net_cost); + vtr::release_memory(proposed_net_cost); + vtr::release_memory(place_move_ctx.bb_coords); + vtr::release_memory(place_move_ctx.bb_num_on_edges); - free_fast_cost_update(); + vtr::release_memory(bb_updated_before); - free_try_swap_structs(); + free_fast_cost_update(); + + free_try_swap_structs(); } static void alloc_and_load_try_swap_structs() { - /* Allocate the local bb_coordinate storage, etc. only once. */ - /* Allocate with size cluster_ctx.clb_nlist.nets().size() for any number of nets affected. */ - auto& cluster_ctx = g_vpr_ctx.clustering(); + /* Allocate the local bb_coordinate storage, etc. only once. */ + /* Allocate with size cluster_ctx.clb_nlist.nets().size() for any number of nets affected. */ + auto &cluster_ctx = g_vpr_ctx.clustering(); - size_t num_nets = cluster_ctx.clb_nlist.nets().size(); + size_t num_nets = cluster_ctx.clb_nlist.nets().size(); - ts_bb_coord_new.resize(num_nets, t_bb()); - ts_bb_edge_new.resize(num_nets, t_bb()); - ts_nets_to_update.resize(num_nets, ClusterNetId::INVALID()); + ts_bb_coord_new.resize(num_nets, t_bb()); + ts_bb_edge_new.resize(num_nets, t_bb()); + ts_nets_to_update.resize(num_nets, ClusterNetId::INVALID()); - auto& place_ctx = g_vpr_ctx.mutable_placement(); - place_ctx.compressed_block_grids = create_compressed_block_grids(); + auto &place_ctx = g_vpr_ctx.mutable_placement(); + place_ctx.compressed_block_grids = create_compressed_block_grids(); } static void free_try_swap_structs() { - vtr::release_memory(ts_bb_coord_new); - vtr::release_memory(ts_bb_edge_new); - vtr::release_memory(ts_nets_to_update); + vtr::release_memory(ts_bb_coord_new); + vtr::release_memory(ts_bb_edge_new); + vtr::release_memory(ts_nets_to_update); - auto& place_ctx = g_vpr_ctx.mutable_placement(); - vtr::release_memory(place_ctx.compressed_block_grids); + auto &place_ctx = g_vpr_ctx.mutable_placement(); + vtr::release_memory(place_ctx.compressed_block_grids); } /* This routine finds the bounding box of each net from scratch (i.e. * * from only the block location information). It updates both the * * coordinate and number of pins on each edge information. It * * should only be called when the bounding box information is not valid. */ -static void get_bb_from_scratch(ClusterNetId net_id, t_bb* coords, t_bb* num_on_edges) { - int pnum, x, y, xmin, xmax, ymin, ymax; - int xmin_edge, xmax_edge, ymin_edge, ymax_edge; - - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.placement(); - auto& device_ctx = g_vpr_ctx.device(); - auto& grid = device_ctx.grid; - - ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); - pnum = net_pin_to_tile_pin_index(net_id, 0); - VTR_ASSERT(pnum >= 0); - x = place_ctx.block_locs[bnum].loc.x + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y + physical_tile_type(bnum)->pin_height_offset[pnum]; - - x = max(min(x, grid.width() - 2), 1); - y = max(min(y, grid.height() - 2), 1); - - xmin = x; - ymin = y; - xmax = x; - ymax = y; - xmin_edge = 1; - ymin_edge = 1; - xmax_edge = 1; - ymax_edge = 1; - - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - bnum = cluster_ctx.clb_nlist.pin_block(pin_id); - pnum = tile_pin_index(pin_id); - x = place_ctx.block_locs[bnum].loc.x + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y + physical_tile_type(bnum)->pin_height_offset[pnum]; - - /* Code below counts IO blocks as being within the 1..grid.width()-2, 1..grid.height()-2 clb array. * - * This is because channels do not go out of the 0..grid.width()-2, 0..grid.height()-2 range, and * - * I always take all channels impinging on the bounding box to be within * - * that bounding box. Hence, this "movement" of IO blocks does not affect * - * the which channels are included within the bounding box, and it * - * simplifies the code a lot. */ - - x = max(min(x, grid.width() - 2), 1); //-2 for no perim channels - y = max(min(y, grid.height() - 2), 1); //-2 for no perim channels - - if (x == xmin) { - xmin_edge++; - } - if (x == xmax) { /* Recall that xmin could equal xmax -- don't use else */ - xmax_edge++; - } else if (x < xmin) { - xmin = x; - xmin_edge = 1; - } else if (x > xmax) { - xmax = x; - xmax_edge = 1; - } - - if (y == ymin) { - ymin_edge++; - } - if (y == ymax) { - ymax_edge++; - } else if (y < ymin) { - ymin = y; - ymin_edge = 1; - } else if (y > ymax) { - ymax = y; - ymax_edge = 1; - } - } - - /* Copy the coordinates and number on edges information into the proper * - * structures. */ - coords->xmin = xmin; - coords->xmax = xmax; - coords->ymin = ymin; - coords->ymax = ymax; - - num_on_edges->xmin = xmin_edge; - num_on_edges->xmax = xmax_edge; - num_on_edges->ymin = ymin_edge; - num_on_edges->ymax = ymax_edge; +static void get_bb_from_scratch(ClusterNetId net_id, t_bb *coords, + t_bb *num_on_edges) { + int pnum, x, y, xmin, xmax, ymin, ymax; + int xmin_edge, xmax_edge, ymin_edge, ymax_edge; + + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_ctx = g_vpr_ctx.placement(); + auto &device_ctx = g_vpr_ctx.device(); + auto &grid = device_ctx.grid; + + ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); + pnum = net_pin_to_tile_pin_index(net_id, 0); + VTR_ASSERT(pnum >= 0); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + x = max(min(x, grid.width() - 2), 1); + y = max(min(y, grid.height() - 2), 1); + + xmin = x; + ymin = y; + xmax = x; + ymax = y; + xmin_edge = 1; + ymin_edge = 1; + xmax_edge = 1; + ymax_edge = 1; + + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + bnum = cluster_ctx.clb_nlist.pin_block(pin_id); + pnum = tile_pin_index(pin_id); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + /* Code below counts IO blocks as being within the 1..grid.width()-2, 1..grid.height()-2 clb array. * + * This is because channels do not go out of the 0..grid.width()-2, 0..grid.height()-2 range, and * + * I always take all channels impinging on the bounding box to be within * + * that bounding box. Hence, this "movement" of IO blocks does not affect * + * the which channels are included within the bounding box, and it * + * simplifies the code a lot. */ + + x = max(min(x, grid.width() - 2), 1); //-2 for no perim channels + y = max(min(y, grid.height() - 2), 1); //-2 for no perim channels + + if (x == xmin) { + xmin_edge++; + } + if (x == xmax) { /* Recall that xmin could equal xmax -- don't use else */ + xmax_edge++; + } else if (x < xmin) { + xmin = x; + xmin_edge = 1; + } else if (x > xmax) { + xmax = x; + xmax_edge = 1; + } + + if (y == ymin) { + ymin_edge++; + } + if (y == ymax) { + ymax_edge++; + } else if (y < ymin) { + ymin = y; + ymin_edge = 1; + } else if (y > ymax) { + ymax = y; + ymax_edge = 1; + } + } + + /* Copy the coordinates and number on edges information into the proper * + * structures. */ + coords->xmin = xmin; + coords->xmax = xmax; + coords->ymin = ymin; + coords->ymax = ymax; + + num_on_edges->xmin = xmin_edge; + num_on_edges->xmax = xmax_edge; + num_on_edges->ymin = ymin_edge; + num_on_edges->ymax = ymax_edge; } static double wirelength_crossing_count(size_t fanout) { - /* Get the expected "crossing count" of a net, based on its number * - * of pins. Extrapolate for very large nets. */ - - if (fanout > 50) { - return 2.7933 + 0.02616 * (fanout - 50); - } else { - return cross_count[fanout - 1]; - } + /* Get the expected "crossing count" of a net, based on its number * + * of pins. Extrapolate for very large nets. */ + + if (fanout > 50) { + return 2.7933 + 0.02616 * (fanout - 50); + } else { + return cross_count[fanout - 1]; + } } -static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb* bbptr) { - /* WMF: Finds the estimate of wirelength due to one net by looking at * - * its coordinate bounding box. */ +static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb *bbptr) { + /* WMF: Finds the estimate of wirelength due to one net by looking at * + * its coordinate bounding box. */ - double ncost, crossing; - auto& cluster_ctx = g_vpr_ctx.clustering(); + double ncost, crossing; + auto &cluster_ctx = g_vpr_ctx.clustering(); - crossing = wirelength_crossing_count(cluster_ctx.clb_nlist.net_pins(net_id).size()); + crossing = wirelength_crossing_count( + cluster_ctx.clb_nlist.net_pins(net_id).size()); - /* Could insert a check for xmin == xmax. In that case, assume * - * connection will be made with no bends and hence no x-cost. * - * Same thing for y-cost. */ + /* Could insert a check for xmin == xmax. In that case, assume * + * connection will be made with no bends and hence no x-cost. * + * Same thing for y-cost. */ - /* Cost = wire length along channel * cross_count / average * - * channel capacity. Do this for x, then y direction and add. */ + /* Cost = wire length along channel * cross_count / average * + * channel capacity. Do this for x, then y direction and add. */ - ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing; + ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing; - ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing; + ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing; - return (ncost); + return (ncost); } -static double get_net_cost(ClusterNetId net_id, t_bb* bbptr) { - /* Finds the cost due to one net by looking at its coordinate bounding * - * box. */ +static double get_net_cost(ClusterNetId net_id, t_bb *bbptr) { + /* Finds the cost due to one net by looking at its coordinate bounding * + * box. */ - double ncost, crossing; - auto& cluster_ctx = g_vpr_ctx.clustering(); + double ncost, crossing; + auto &cluster_ctx = g_vpr_ctx.clustering(); - crossing = wirelength_crossing_count(cluster_ctx.clb_nlist.net_pins(net_id).size()); + crossing = wirelength_crossing_count( + cluster_ctx.clb_nlist.net_pins(net_id).size()); - /* Could insert a check for xmin == xmax. In that case, assume * - * connection will be made with no bends and hence no x-cost. * - * Same thing for y-cost. */ + /* Could insert a check for xmin == xmax. In that case, assume * + * connection will be made with no bends and hence no x-cost. * + * Same thing for y-cost. */ - /* Cost = wire length along channel * cross_count / average * - * channel capacity. Do this for x, then y direction and add. */ + /* Cost = wire length along channel * cross_count / average * + * channel capacity. Do this for x, then y direction and add. */ - ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing - * chanx_place_cost_fac[bbptr->ymax][bbptr->ymin - 1]; + ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing + * chanx_place_cost_fac[bbptr->ymax][bbptr->ymin - 1]; - ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing - * chany_place_cost_fac[bbptr->xmax][bbptr->xmin - 1]; + ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing + * chany_place_cost_fac[bbptr->xmax][bbptr->xmin - 1]; - return (ncost); + return (ncost); } /* Finds the bounding box of a net and stores its coordinates in the * @@ -2277,514 +2273,546 @@ static double get_net_cost(ClusterNetId net_id, t_bb* bbptr) { * Currently assumes channels on both sides of the CLBs forming the * * edges of the bounding box can be used. Essentially, I am assuming * * the pins always lie on the outside of the bounding box. */ -static void get_non_updateable_bb(ClusterNetId net_id, t_bb* bb_coord_new) { - //TODO: account for multiple physical pin instances per logical pin - - int xmax, ymax, xmin, ymin, x, y; - int pnum; - - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.placement(); - auto& device_ctx = g_vpr_ctx.device(); - - ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); - pnum = net_pin_to_tile_pin_index(net_id, 0); - x = place_ctx.block_locs[bnum].loc.x + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y + physical_tile_type(bnum)->pin_height_offset[pnum]; - - xmin = x; - ymin = y; - xmax = x; - ymax = y; - - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - bnum = cluster_ctx.clb_nlist.pin_block(pin_id); - pnum = tile_pin_index(pin_id); - x = place_ctx.block_locs[bnum].loc.x + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y + physical_tile_type(bnum)->pin_height_offset[pnum]; - - if (x < xmin) { - xmin = x; - } else if (x > xmax) { - xmax = x; - } - - if (y < ymin) { - ymin = y; - } else if (y > ymax) { - ymax = y; - } - } - - /* Now I've found the coordinates of the bounding box. There are no * - * channels beyond device_ctx.grid.width()-2 and * - * device_ctx.grid.height() - 2, so I want to clip to that. As well,* - * since I'll always include the channel immediately below and the * - * channel immediately to the left of the bounding box, I want to * - * clip to 1 in both directions as well (since minimum channel index * - * is 0). See route_common.cpp for a channel diagram. */ - - bb_coord_new->xmin = max(min(xmin, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - bb_coord_new->ymin = max(min(ymin, device_ctx.grid.height() - 2), 1); //-2 for no perim channels - bb_coord_new->xmax = max(min(xmax, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - bb_coord_new->ymax = max(min(ymax, device_ctx.grid.height() - 2), 1); //-2 for no perim channels +static void get_non_updateable_bb(ClusterNetId net_id, t_bb *bb_coord_new) { + //TODO: account for multiple physical pin instances per logical pin + + int xmax, ymax, xmin, ymin, x, y; + int pnum; + + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_ctx = g_vpr_ctx.placement(); + auto &device_ctx = g_vpr_ctx.device(); + + ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); + pnum = net_pin_to_tile_pin_index(net_id, 0); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + xmin = x; + ymin = y; + xmax = x; + ymax = y; + + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + bnum = cluster_ctx.clb_nlist.pin_block(pin_id); + pnum = tile_pin_index(pin_id); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + if (x < xmin) { + xmin = x; + } else if (x > xmax) { + xmax = x; + } + + if (y < ymin) { + ymin = y; + } else if (y > ymax) { + ymax = y; + } + } + + /* Now I've found the coordinates of the bounding box. There are no * + * channels beyond device_ctx.grid.width()-2 and * + * device_ctx.grid.height() - 2, so I want to clip to that. As well,* + * since I'll always include the channel immediately below and the * + * channel immediately to the left of the bounding box, I want to * + * clip to 1 in both directions as well (since minimum channel index * + * is 0). See route_common.cpp for a channel diagram. */ + + bb_coord_new->xmin = max(min(xmin, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + bb_coord_new->ymin = max(min(ymin, device_ctx.grid.height() - 2), 1); //-2 for no perim channels + bb_coord_new->xmax = max(min(xmax, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + bb_coord_new->ymax = max(min(ymax, device_ctx.grid.height() - 2), 1); //-2 for no perim channels } -static void update_bb(ClusterNetId net_id, t_bb* bb_coord_new, t_bb* bb_edge_new, int xold, int yold, int xnew, int ynew) { - /* Updates the bounding box of a net by storing its coordinates in * - * the bb_coord_new data structure and the number of blocks on each * - * edge in the bb_edge_new data structure. This routine should only * - * be called for large nets, since it has some overhead relative to * - * just doing a brute force bounding box calculation. The bounding * - * box coordinate and edge information for inet must be valid before * - * this routine is called. * - * Currently assumes channels on both sides of the CLBs forming the * - * edges of the bounding box can be used. Essentially, I am assuming * - * the pins always lie on the outside of the bounding box. * - * The x and y coordinates are the pin's x and y coordinates. */ - /* IO blocks are considered to be one cell in for simplicity. */ - //TODO: account for multiple physical pin instances per logical pin - - const t_bb *curr_bb_edge, *curr_bb_coord; - - auto& device_ctx = g_vpr_ctx.device(); - auto& place_move_ctx = g_placer_ctx.move(); - - xnew = max(min(xnew, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - ynew = max(min(ynew, device_ctx.grid.height() - 2), 1); //-2 for no perim channels - xold = max(min(xold, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - yold = max(min(yold, device_ctx.grid.height() - 2), 1); //-2 for no perim channels - - /* Check if the net had been updated before. */ - if (bb_updated_before[net_id] == GOT_FROM_SCRATCH) { - /* The net had been updated from scratch, DO NOT update again! */ - return; - } else if (bb_updated_before[net_id] == NOT_UPDATED_YET) { - /* The net had NOT been updated before, could use the old values */ - curr_bb_coord = &place_move_ctx.bb_coords[net_id]; - curr_bb_edge = &place_move_ctx.bb_num_on_edges[net_id]; - bb_updated_before[net_id] = UPDATED_ONCE; - } else { - /* The net had been updated before, must use the new values */ - curr_bb_coord = bb_coord_new; - curr_bb_edge = bb_edge_new; - } - - /* Check if I can update the bounding box incrementally. */ - - if (xnew < xold) { /* Move to left. */ - - /* Update the xmax fields for coordinates and number of edges first. */ - - if (xold == curr_bb_coord->xmax) { /* Old position at xmax. */ - if (curr_bb_edge->xmax == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->xmax = curr_bb_edge->xmax - 1; - bb_coord_new->xmax = curr_bb_coord->xmax; - } - } else { /* Move to left, old postion was not at xmax. */ - bb_coord_new->xmax = curr_bb_coord->xmax; - bb_edge_new->xmax = curr_bb_edge->xmax; - } - - /* Now do the xmin fields for coordinates and number of edges. */ - - if (xnew < curr_bb_coord->xmin) { /* Moved past xmin */ - bb_coord_new->xmin = xnew; - bb_edge_new->xmin = 1; - } else if (xnew == curr_bb_coord->xmin) { /* Moved to xmin */ - bb_coord_new->xmin = xnew; - bb_edge_new->xmin = curr_bb_edge->xmin + 1; - } else { /* Xmin unchanged. */ - bb_coord_new->xmin = curr_bb_coord->xmin; - bb_edge_new->xmin = curr_bb_edge->xmin; - } - /* End of move to left case. */ - - } else if (xnew > xold) { /* Move to right. */ - - /* Update the xmin fields for coordinates and number of edges first. */ - - if (xold == curr_bb_coord->xmin) { /* Old position at xmin. */ - if (curr_bb_edge->xmin == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->xmin = curr_bb_edge->xmin - 1; - bb_coord_new->xmin = curr_bb_coord->xmin; - } - } else { /* Move to right, old position was not at xmin. */ - bb_coord_new->xmin = curr_bb_coord->xmin; - bb_edge_new->xmin = curr_bb_edge->xmin; - } - - /* Now do the xmax fields for coordinates and number of edges. */ - - if (xnew > curr_bb_coord->xmax) { /* Moved past xmax. */ - bb_coord_new->xmax = xnew; - bb_edge_new->xmax = 1; - } else if (xnew == curr_bb_coord->xmax) { /* Moved to xmax */ - bb_coord_new->xmax = xnew; - bb_edge_new->xmax = curr_bb_edge->xmax + 1; - } else { /* Xmax unchanged. */ - bb_coord_new->xmax = curr_bb_coord->xmax; - bb_edge_new->xmax = curr_bb_edge->xmax; - } - /* End of move to right case. */ - - } else { /* xnew == xold -- no x motion. */ - bb_coord_new->xmin = curr_bb_coord->xmin; - bb_coord_new->xmax = curr_bb_coord->xmax; - bb_edge_new->xmin = curr_bb_edge->xmin; - bb_edge_new->xmax = curr_bb_edge->xmax; - } - - /* Now account for the y-direction motion. */ - - if (ynew < yold) { /* Move down. */ - - /* Update the ymax fields for coordinates and number of edges first. */ - - if (yold == curr_bb_coord->ymax) { /* Old position at ymax. */ - if (curr_bb_edge->ymax == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->ymax = curr_bb_edge->ymax - 1; - bb_coord_new->ymax = curr_bb_coord->ymax; - } - } else { /* Move down, old postion was not at ymax. */ - bb_coord_new->ymax = curr_bb_coord->ymax; - bb_edge_new->ymax = curr_bb_edge->ymax; - } - - /* Now do the ymin fields for coordinates and number of edges. */ - - if (ynew < curr_bb_coord->ymin) { /* Moved past ymin */ - bb_coord_new->ymin = ynew; - bb_edge_new->ymin = 1; - } else if (ynew == curr_bb_coord->ymin) { /* Moved to ymin */ - bb_coord_new->ymin = ynew; - bb_edge_new->ymin = curr_bb_edge->ymin + 1; - } else { /* ymin unchanged. */ - bb_coord_new->ymin = curr_bb_coord->ymin; - bb_edge_new->ymin = curr_bb_edge->ymin; - } - /* End of move down case. */ - - } else if (ynew > yold) { /* Moved up. */ - - /* Update the ymin fields for coordinates and number of edges first. */ - - if (yold == curr_bb_coord->ymin) { /* Old position at ymin. */ - if (curr_bb_edge->ymin == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->ymin = curr_bb_edge->ymin - 1; - bb_coord_new->ymin = curr_bb_coord->ymin; - } - } else { /* Moved up, old position was not at ymin. */ - bb_coord_new->ymin = curr_bb_coord->ymin; - bb_edge_new->ymin = curr_bb_edge->ymin; - } - - /* Now do the ymax fields for coordinates and number of edges. */ - - if (ynew > curr_bb_coord->ymax) { /* Moved past ymax. */ - bb_coord_new->ymax = ynew; - bb_edge_new->ymax = 1; - } else if (ynew == curr_bb_coord->ymax) { /* Moved to ymax */ - bb_coord_new->ymax = ynew; - bb_edge_new->ymax = curr_bb_edge->ymax + 1; - } else { /* ymax unchanged. */ - bb_coord_new->ymax = curr_bb_coord->ymax; - bb_edge_new->ymax = curr_bb_edge->ymax; - } - /* End of move up case. */ - - } else { /* ynew == yold -- no y motion. */ - bb_coord_new->ymin = curr_bb_coord->ymin; - bb_coord_new->ymax = curr_bb_coord->ymax; - bb_edge_new->ymin = curr_bb_edge->ymin; - bb_edge_new->ymax = curr_bb_edge->ymax; - } - - if (bb_updated_before[net_id] == NOT_UPDATED_YET) { - bb_updated_before[net_id] = UPDATED_ONCE; - } +static void update_bb(ClusterNetId net_id, t_bb *bb_coord_new, + t_bb *bb_edge_new, int xold, int yold, int xnew, int ynew) { + /* Updates the bounding box of a net by storing its coordinates in * + * the bb_coord_new data structure and the number of blocks on each * + * edge in the bb_edge_new data structure. This routine should only * + * be called for large nets, since it has some overhead relative to * + * just doing a brute force bounding box calculation. The bounding * + * box coordinate and edge information for inet must be valid before * + * this routine is called. * + * Currently assumes channels on both sides of the CLBs forming the * + * edges of the bounding box can be used. Essentially, I am assuming * + * the pins always lie on the outside of the bounding box. * + * The x and y coordinates are the pin's x and y coordinates. */ + /* IO blocks are considered to be one cell in for simplicity. */ + //TODO: account for multiple physical pin instances per logical pin + const t_bb *curr_bb_edge, *curr_bb_coord; + + auto &device_ctx = g_vpr_ctx.device(); + auto &place_move_ctx = g_placer_ctx.move(); + + xnew = max(min(xnew, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + ynew = max(min(ynew, device_ctx.grid.height() - 2), 1); //-2 for no perim channels + xold = max(min(xold, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + yold = max(min(yold, device_ctx.grid.height() - 2), 1); //-2 for no perim channels + + /* Check if the net had been updated before. */ + if (bb_updated_before[net_id] == GOT_FROM_SCRATCH) { + /* The net had been updated from scratch, DO NOT update again! */ + return; + } else if (bb_updated_before[net_id] == NOT_UPDATED_YET) { + /* The net had NOT been updated before, could use the old values */ + curr_bb_coord = &place_move_ctx.bb_coords[net_id]; + curr_bb_edge = &place_move_ctx.bb_num_on_edges[net_id]; + bb_updated_before[net_id] = UPDATED_ONCE; + } else { + /* The net had been updated before, must use the new values */ + curr_bb_coord = bb_coord_new; + curr_bb_edge = bb_edge_new; + } + + /* Check if I can update the bounding box incrementally. */ + + if (xnew < xold) { /* Move to left. */ + + /* Update the xmax fields for coordinates and number of edges first. */ + + if (xold == curr_bb_coord->xmax) { /* Old position at xmax. */ + if (curr_bb_edge->xmax == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->xmax = curr_bb_edge->xmax - 1; + bb_coord_new->xmax = curr_bb_coord->xmax; + } + } else { /* Move to left, old postion was not at xmax. */ + bb_coord_new->xmax = curr_bb_coord->xmax; + bb_edge_new->xmax = curr_bb_edge->xmax; + } + + /* Now do the xmin fields for coordinates and number of edges. */ + + if (xnew < curr_bb_coord->xmin) { /* Moved past xmin */ + bb_coord_new->xmin = xnew; + bb_edge_new->xmin = 1; + } else if (xnew == curr_bb_coord->xmin) { /* Moved to xmin */ + bb_coord_new->xmin = xnew; + bb_edge_new->xmin = curr_bb_edge->xmin + 1; + } else { /* Xmin unchanged. */ + bb_coord_new->xmin = curr_bb_coord->xmin; + bb_edge_new->xmin = curr_bb_edge->xmin; + } + /* End of move to left case. */ + + } else if (xnew > xold) { /* Move to right. */ + + /* Update the xmin fields for coordinates and number of edges first. */ + + if (xold == curr_bb_coord->xmin) { /* Old position at xmin. */ + if (curr_bb_edge->xmin == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->xmin = curr_bb_edge->xmin - 1; + bb_coord_new->xmin = curr_bb_coord->xmin; + } + } else { /* Move to right, old position was not at xmin. */ + bb_coord_new->xmin = curr_bb_coord->xmin; + bb_edge_new->xmin = curr_bb_edge->xmin; + } + + /* Now do the xmax fields for coordinates and number of edges. */ + + if (xnew > curr_bb_coord->xmax) { /* Moved past xmax. */ + bb_coord_new->xmax = xnew; + bb_edge_new->xmax = 1; + } else if (xnew == curr_bb_coord->xmax) { /* Moved to xmax */ + bb_coord_new->xmax = xnew; + bb_edge_new->xmax = curr_bb_edge->xmax + 1; + } else { /* Xmax unchanged. */ + bb_coord_new->xmax = curr_bb_coord->xmax; + bb_edge_new->xmax = curr_bb_edge->xmax; + } + /* End of move to right case. */ + + } else { /* xnew == xold -- no x motion. */ + bb_coord_new->xmin = curr_bb_coord->xmin; + bb_coord_new->xmax = curr_bb_coord->xmax; + bb_edge_new->xmin = curr_bb_edge->xmin; + bb_edge_new->xmax = curr_bb_edge->xmax; + } + + /* Now account for the y-direction motion. */ + + if (ynew < yold) { /* Move down. */ + + /* Update the ymax fields for coordinates and number of edges first. */ + + if (yold == curr_bb_coord->ymax) { /* Old position at ymax. */ + if (curr_bb_edge->ymax == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->ymax = curr_bb_edge->ymax - 1; + bb_coord_new->ymax = curr_bb_coord->ymax; + } + } else { /* Move down, old postion was not at ymax. */ + bb_coord_new->ymax = curr_bb_coord->ymax; + bb_edge_new->ymax = curr_bb_edge->ymax; + } + + /* Now do the ymin fields for coordinates and number of edges. */ + + if (ynew < curr_bb_coord->ymin) { /* Moved past ymin */ + bb_coord_new->ymin = ynew; + bb_edge_new->ymin = 1; + } else if (ynew == curr_bb_coord->ymin) { /* Moved to ymin */ + bb_coord_new->ymin = ynew; + bb_edge_new->ymin = curr_bb_edge->ymin + 1; + } else { /* ymin unchanged. */ + bb_coord_new->ymin = curr_bb_coord->ymin; + bb_edge_new->ymin = curr_bb_edge->ymin; + } + /* End of move down case. */ + + } else if (ynew > yold) { /* Moved up. */ + + /* Update the ymin fields for coordinates and number of edges first. */ + + if (yold == curr_bb_coord->ymin) { /* Old position at ymin. */ + if (curr_bb_edge->ymin == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->ymin = curr_bb_edge->ymin - 1; + bb_coord_new->ymin = curr_bb_coord->ymin; + } + } else { /* Moved up, old position was not at ymin. */ + bb_coord_new->ymin = curr_bb_coord->ymin; + bb_edge_new->ymin = curr_bb_edge->ymin; + } + + /* Now do the ymax fields for coordinates and number of edges. */ + + if (ynew > curr_bb_coord->ymax) { /* Moved past ymax. */ + bb_coord_new->ymax = ynew; + bb_edge_new->ymax = 1; + } else if (ynew == curr_bb_coord->ymax) { /* Moved to ymax */ + bb_coord_new->ymax = ynew; + bb_edge_new->ymax = curr_bb_edge->ymax + 1; + } else { /* ymax unchanged. */ + bb_coord_new->ymax = curr_bb_coord->ymax; + bb_edge_new->ymax = curr_bb_edge->ymax; + } + /* End of move up case. */ + + } else { /* ynew == yold -- no y motion. */ + bb_coord_new->ymin = curr_bb_coord->ymin; + bb_coord_new->ymax = curr_bb_coord->ymax; + bb_edge_new->ymin = curr_bb_edge->ymin; + bb_edge_new->ymax = curr_bb_edge->ymax; + } + + if (bb_updated_before[net_id] == NOT_UPDATED_YET) { + bb_updated_before[net_id] = UPDATED_ONCE; + } } static void free_fast_cost_update() { - auto& device_ctx = g_vpr_ctx.device(); - - for (size_t i = 0; i < device_ctx.grid.height(); i++) { - free(chanx_place_cost_fac[i]); - } - free(chanx_place_cost_fac); - chanx_place_cost_fac = nullptr; - - for (size_t i = 0; i < device_ctx.grid.width(); i++) { - free(chany_place_cost_fac[i]); - } - free(chany_place_cost_fac); - chany_place_cost_fac = nullptr; + auto &device_ctx = g_vpr_ctx.device(); + + for (size_t i = 0; i < device_ctx.grid.height(); i++) { + free(chanx_place_cost_fac[i]); + } + free(chanx_place_cost_fac); + chanx_place_cost_fac = nullptr; + + for (size_t i = 0; i < device_ctx.grid.width(); i++) { + free(chany_place_cost_fac[i]); + } + free(chany_place_cost_fac); + chany_place_cost_fac = nullptr; } static void alloc_and_load_for_fast_cost_update(float place_cost_exp) { - /* Allocates and loads the chanx_place_cost_fac and chany_place_cost_fac * - * arrays with the inverse of the average number of tracks per channel * - * between [subhigh] and [sublow]. This is only useful for the cost * - * function that takes the length of the net bounding box in each * - * dimension divided by the average number of tracks in that direction. * - * For other cost functions, you don't have to bother calling this * - * routine; when using the cost function described above, however, you * - * must always call this routine after you call init_chan and before * - * you do any placement cost determination. The place_cost_exp factor * - * specifies to what power the width of the channel should be taken -- * - * larger numbers make narrower channels more expensive. */ - - auto& device_ctx = g_vpr_ctx.device(); - - /* Access arrays below as chan?_place_cost_fac[subhigh][sublow]. Since * - * subhigh must be greater than or equal to sublow, we only need to * - * allocate storage for the lower half of a matrix. */ - - chanx_place_cost_fac = (float**)vtr::malloc((device_ctx.grid.height()) * sizeof(float*)); - for (size_t i = 0; i < device_ctx.grid.height(); i++) - chanx_place_cost_fac[i] = (float*)vtr::malloc((i + 1) * sizeof(float)); - - chany_place_cost_fac = (float**)vtr::malloc((device_ctx.grid.width() + 1) * sizeof(float*)); - for (size_t i = 0; i < device_ctx.grid.width(); i++) - chany_place_cost_fac[i] = (float*)vtr::malloc((i + 1) * sizeof(float)); - - /* First compute the number of tracks between channel high and channel * - * low, inclusive, in an efficient manner. */ - - chanx_place_cost_fac[0][0] = device_ctx.chan_width.x_list[0]; - - for (size_t high = 1; high < device_ctx.grid.height(); high++) { - chanx_place_cost_fac[high][high] = device_ctx.chan_width.x_list[high]; - for (size_t low = 0; low < high; low++) { - chanx_place_cost_fac[high][low] = chanx_place_cost_fac[high - 1][low] + device_ctx.chan_width.x_list[high]; - } - } - - /* Now compute the inverse of the average number of tracks per channel * - * between high and low. The cost function divides by the average * - * number of tracks per channel, so by storing the inverse I convert * - * this to a faster multiplication. Take this final number to the * - * place_cost_exp power -- numbers other than one mean this is no * - * longer a simple "average number of tracks"; it is some power of * - * that, allowing greater penalization of narrow channels. */ - - for (size_t high = 0; high < device_ctx.grid.height(); high++) - for (size_t low = 0; low <= high; low++) { - /* Since we will divide the wiring cost by the average channel * - * capacity between high and low, having only 0 width channels * - * will result in infinite wiring capacity normalization * - * factor, and extremely bad placer behaviour. Hence we change * - * this to a small (1 track) channel capacity instead. */ - if (chanx_place_cost_fac[high][low] == 0.0f) { - VTR_LOG_WARN("CHANX place cost fac is 0 at %d %d\n", high, low); - chanx_place_cost_fac[high][low] = 1.0f; - } - - chanx_place_cost_fac[high][low] = (high - low + 1.) - / chanx_place_cost_fac[high][low]; - chanx_place_cost_fac[high][low] = pow((double)chanx_place_cost_fac[high][low], (double)place_cost_exp); - } - - /* Now do the same thing for the y-directed channels. First get the * - * number of tracks between channel high and channel low, inclusive. */ - - chany_place_cost_fac[0][0] = device_ctx.chan_width.y_list[0]; - - for (size_t high = 1; high < device_ctx.grid.width(); high++) { - chany_place_cost_fac[high][high] = device_ctx.chan_width.y_list[high]; - for (size_t low = 0; low < high; low++) { - chany_place_cost_fac[high][low] = chany_place_cost_fac[high - 1][low] + device_ctx.chan_width.y_list[high]; - } - } - - /* Now compute the inverse of the average number of tracks per channel * - * between high and low. Take to specified power. */ - - for (size_t high = 0; high < device_ctx.grid.width(); high++) - for (size_t low = 0; low <= high; low++) { - /* Since we will divide the wiring cost by the average channel * - * capacity between high and low, having only 0 width channels * - * will result in infinite wiring capacity normalization * - * factor, and extremely bad placer behaviour. Hence we change * - * this to a small (1 track) channel capacity instead. */ - if (chany_place_cost_fac[high][low] == 0.0f) { - VTR_LOG_WARN("CHANY place cost fac is 0 at %d %d\n", high, low); - chany_place_cost_fac[high][low] = 1.0f; - } - - chany_place_cost_fac[high][low] = (high - low + 1.) - / chany_place_cost_fac[high][low]; - chany_place_cost_fac[high][low] = pow((double)chany_place_cost_fac[high][low], (double)place_cost_exp); - } + /* Allocates and loads the chanx_place_cost_fac and chany_place_cost_fac * + * arrays with the inverse of the average number of tracks per channel * + * between [subhigh] and [sublow]. This is only useful for the cost * + * function that takes the length of the net bounding box in each * + * dimension divided by the average number of tracks in that direction. * + * For other cost functions, you don't have to bother calling this * + * routine; when using the cost function described above, however, you * + * must always call this routine after you call init_chan and before * + * you do any placement cost determination. The place_cost_exp factor * + * specifies to what power the width of the channel should be taken -- * + * larger numbers make narrower channels more expensive. */ + + auto &device_ctx = g_vpr_ctx.device(); + + /* Access arrays below as chan?_place_cost_fac[subhigh][sublow]. Since * + * subhigh must be greater than or equal to sublow, we only need to * + * allocate storage for the lower half of a matrix. */ + + chanx_place_cost_fac = (float**) vtr::malloc( + (device_ctx.grid.height()) * sizeof(float*)); + for (size_t i = 0; i < device_ctx.grid.height(); i++) + chanx_place_cost_fac[i] = (float*) vtr::malloc((i + 1) * sizeof(float)); + + chany_place_cost_fac = (float**) vtr::malloc( + (device_ctx.grid.width() + 1) * sizeof(float*)); + for (size_t i = 0; i < device_ctx.grid.width(); i++) + chany_place_cost_fac[i] = (float*) vtr::malloc((i + 1) * sizeof(float)); + + /* First compute the number of tracks between channel high and channel * + * low, inclusive, in an efficient manner. */ + + chanx_place_cost_fac[0][0] = device_ctx.chan_width.x_list[0]; + + for (size_t high = 1; high < device_ctx.grid.height(); high++) { + chanx_place_cost_fac[high][high] = device_ctx.chan_width.x_list[high]; + for (size_t low = 0; low < high; low++) { + chanx_place_cost_fac[high][low] = + chanx_place_cost_fac[high - 1][low] + + device_ctx.chan_width.x_list[high]; + } + } + + /* Now compute the inverse of the average number of tracks per channel * + * between high and low. The cost function divides by the average * + * number of tracks per channel, so by storing the inverse I convert * + * this to a faster multiplication. Take this final number to the * + * place_cost_exp power -- numbers other than one mean this is no * + * longer a simple "average number of tracks"; it is some power of * + * that, allowing greater penalization of narrow channels. */ + + for (size_t high = 0; high < device_ctx.grid.height(); high++) + for (size_t low = 0; low <= high; low++) { + /* Since we will divide the wiring cost by the average channel * + * capacity between high and low, having only 0 width channels * + * will result in infinite wiring capacity normalization * + * factor, and extremely bad placer behaviour. Hence we change * + * this to a small (1 track) channel capacity instead. */ + if (chanx_place_cost_fac[high][low] == 0.0f) { + VTR_LOG_WARN("CHANX place cost fac is 0 at %d %d\n", high, low); + chanx_place_cost_fac[high][low] = 1.0f; + } + + chanx_place_cost_fac[high][low] = (high - low + 1.) + / chanx_place_cost_fac[high][low]; + chanx_place_cost_fac[high][low] = pow( + (double) chanx_place_cost_fac[high][low], + (double) place_cost_exp); + } + + /* Now do the same thing for the y-directed channels. First get the * + * number of tracks between channel high and channel low, inclusive. */ + + chany_place_cost_fac[0][0] = device_ctx.chan_width.y_list[0]; + + for (size_t high = 1; high < device_ctx.grid.width(); high++) { + chany_place_cost_fac[high][high] = device_ctx.chan_width.y_list[high]; + for (size_t low = 0; low < high; low++) { + chany_place_cost_fac[high][low] = + chany_place_cost_fac[high - 1][low] + + device_ctx.chan_width.y_list[high]; + } + } + + /* Now compute the inverse of the average number of tracks per channel * + * between high and low. Take to specified power. */ + + for (size_t high = 0; high < device_ctx.grid.width(); high++) + for (size_t low = 0; low <= high; low++) { + /* Since we will divide the wiring cost by the average channel * + * capacity between high and low, having only 0 width channels * + * will result in infinite wiring capacity normalization * + * factor, and extremely bad placer behaviour. Hence we change * + * this to a small (1 track) channel capacity instead. */ + if (chany_place_cost_fac[high][low] == 0.0f) { + VTR_LOG_WARN("CHANY place cost fac is 0 at %d %d\n", high, low); + chany_place_cost_fac[high][low] = 1.0f; + } + + chany_place_cost_fac[high][low] = (high - low + 1.) + / chany_place_cost_fac[high][low]; + chany_place_cost_fac[high][low] = pow( + (double) chany_place_cost_fac[high][low], + (double) place_cost_exp); + } } -static void check_place(const t_placer_costs& costs, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - const t_place_algorithm& place_algorithm) { - /* Checks that the placement has not confused our data structures. * - * i.e. the clb and block structures agree about the locations of * - * every block, blocks are in legal spots, etc. Also recomputes * - * the final placement cost from scratch and makes sure it is * - * within roundoff of what we think the cost is. */ - - int error = 0; - - error += check_placement_consistency(); - error += check_placement_costs(costs, delay_model, criticalities, place_algorithm); - error += check_placement_floorplanning(); - - if (error == 0) { - VTR_LOG("\n"); - VTR_LOG("Completed placement consistency check successfully.\n"); - - } else { - VPR_ERROR(VPR_ERROR_PLACE, - "\nCompleted placement consistency check, %d errors found.\n" - "Aborting program.\n", - error); - } +static void check_place(const t_placer_costs &costs, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, + const t_place_algorithm &place_algorithm) { + /* Checks that the placement has not confused our data structures. * + * i.e. the clb and block structures agree about the locations of * + * every block, blocks are in legal spots, etc. Also recomputes * + * the final placement cost from scratch and makes sure it is * + * within roundoff of what we think the cost is. */ + + int error = 0; + + error += check_placement_consistency(); + error += check_placement_costs(costs, delay_model, criticalities, + place_algorithm); + error += check_placement_floorplanning(); + + if (error == 0) { + VTR_LOG("\n"); + VTR_LOG("Completed placement consistency check successfully.\n"); + + } else { + VPR_ERROR(VPR_ERROR_PLACE, + "\nCompleted placement consistency check, %d errors found.\n" + "Aborting program.\n", error); + } } -static int check_placement_costs(const t_placer_costs& costs, - const PlaceDelayModel* delay_model, - const PlacerCriticalities* criticalities, - const t_place_algorithm& place_algorithm) { - int error = 0; - double bb_cost_check; - double timing_cost_check; - - bb_cost_check = comp_bb_cost(CHECK); - if (fabs(bb_cost_check - costs.bb_cost) > costs.bb_cost * ERROR_TOL) { - VTR_LOG_ERROR("bb_cost_check: %g and bb_cost: %g differ in check_place.\n", - bb_cost_check, costs.bb_cost); - error++; - } - - if (place_algorithm.is_timing_driven()) { - comp_td_costs(delay_model, *criticalities, &timing_cost_check); - //VTR_LOG("timing_cost recomputed from scratch: %g\n", timing_cost_check); - if (fabs(timing_cost_check - costs.timing_cost) > costs.timing_cost * ERROR_TOL) { - VTR_LOG_ERROR("timing_cost_check: %g and timing_cost: %g differ in check_place.\n", - timing_cost_check, costs.timing_cost); - error++; - } - } - return error; +static int check_placement_costs(const t_placer_costs &costs, + const PlaceDelayModel *delay_model, + const PlacerCriticalities *criticalities, + const t_place_algorithm &place_algorithm) { + int error = 0; + double bb_cost_check; + double timing_cost_check; + + bb_cost_check = comp_bb_cost(CHECK); + if (fabs(bb_cost_check - costs.bb_cost) > costs.bb_cost * ERROR_TOL) { + VTR_LOG_ERROR( + "bb_cost_check: %g and bb_cost: %g differ in check_place.\n", + bb_cost_check, costs.bb_cost); + error++; + } + + if (place_algorithm.is_timing_driven()) { + comp_td_costs(delay_model, *criticalities, &timing_cost_check); + //VTR_LOG("timing_cost recomputed from scratch: %g\n", timing_cost_check); + if (fabs( + timing_cost_check + - costs.timing_cost) > costs.timing_cost * ERROR_TOL) { + VTR_LOG_ERROR( + "timing_cost_check: %g and timing_cost: %g differ in check_place.\n", + timing_cost_check, costs.timing_cost); + error++; + } + } + return error; } static int check_placement_consistency() { - return check_block_placement_consistency() + check_macro_placement_consistency(); + return check_block_placement_consistency() + + check_macro_placement_consistency(); } static int check_block_placement_consistency() { - int error = 0; - - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.placement(); - auto& device_ctx = g_vpr_ctx.device(); - - vtr::vector bdone(cluster_ctx.clb_nlist.blocks().size(), 0); - - /* Step through device grid and placement. Check it against blocks */ - for (size_t i = 0; i < device_ctx.grid.width(); i++) - for (size_t j = 0; j < device_ctx.grid.height(); j++) { - if (place_ctx.grid_blocks[i][j].usage > device_ctx.grid[i][j].type->capacity) { - VTR_LOG_ERROR("Block at grid location (%zu,%zu) overused. Usage is %d.\n", - i, j, place_ctx.grid_blocks[i][j].usage); - error++; - } - int usage_check = 0; - for (int k = 0; k < device_ctx.grid[i][j].type->capacity; k++) { - auto bnum = place_ctx.grid_blocks[i][j].blocks[k]; - if (EMPTY_BLOCK_ID == bnum || INVALID_BLOCK_ID == bnum) - continue; - - auto logical_block = cluster_ctx.clb_nlist.block_type(bnum); - auto physical_tile = device_ctx.grid[i][j].type; - - if (physical_tile_type(bnum) != physical_tile) { - VTR_LOG_ERROR("Block %zu type (%s) does not match grid location (%zu,%zu) type (%s).\n", - size_t(bnum), logical_block->name, i, j, physical_tile->name); - error++; - } - - auto& loc = place_ctx.block_locs[bnum].loc; - if (loc.x != int(i) || loc.y != int(j) || !is_sub_tile_compatible(physical_tile, logical_block, loc.sub_tile)) { - VTR_LOG_ERROR("Block %zu's location is (%d,%d,%d) but found in grid at (%zu,%zu,%d).\n", - size_t(bnum), loc.x, loc.y, loc.sub_tile, - i, j, k); - error++; - } - ++usage_check; - bdone[bnum]++; - } - if (usage_check != place_ctx.grid_blocks[i][j].usage) { - VTR_LOG_ERROR("Location (%zu,%zu) usage is %d, but has actual usage %d.\n", - i, j, place_ctx.grid_blocks[i][j].usage, usage_check); - error++; - } - } - - /* Check that every block exists in the device_ctx.grid and cluster_ctx.blocks arrays somewhere. */ - for (auto blk_id : cluster_ctx.clb_nlist.blocks()) - if (bdone[blk_id] != 1) { - VTR_LOG_ERROR("Block %zu listed %d times in data structures.\n", - size_t(blk_id), bdone[blk_id]); - error++; - } - - return error; + int error = 0; + + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &place_ctx = g_vpr_ctx.placement(); + auto &device_ctx = g_vpr_ctx.device(); + + vtr::vector bdone( + cluster_ctx.clb_nlist.blocks().size(), 0); + + /* Step through device grid and placement. Check it against blocks */ + for (size_t i = 0; i < device_ctx.grid.width(); i++) + for (size_t j = 0; j < device_ctx.grid.height(); j++) { + if (place_ctx.grid_blocks[i][j].usage + > device_ctx.grid[i][j].type->capacity) { + VTR_LOG_ERROR( + "Block at grid location (%zu,%zu) overused. Usage is %d.\n", + i, j, place_ctx.grid_blocks[i][j].usage); + error++; + } + int usage_check = 0; + for (int k = 0; k < device_ctx.grid[i][j].type->capacity; k++) { + auto bnum = place_ctx.grid_blocks[i][j].blocks[k]; + if (EMPTY_BLOCK_ID == bnum || INVALID_BLOCK_ID == bnum) + continue; + + auto logical_block = cluster_ctx.clb_nlist.block_type(bnum); + auto physical_tile = device_ctx.grid[i][j].type; + + if (physical_tile_type(bnum) != physical_tile) { + VTR_LOG_ERROR( + "Block %zu type (%s) does not match grid location (%zu,%zu) type (%s).\n", + size_t(bnum), logical_block->name, i, j, + physical_tile->name); + error++; + } + + auto &loc = place_ctx.block_locs[bnum].loc; + if (loc.x != int(i) || loc.y != int(j) + || !is_sub_tile_compatible(physical_tile, logical_block, + loc.sub_tile)) { + VTR_LOG_ERROR( + "Block %zu's location is (%d,%d,%d) but found in grid at (%zu,%zu,%d).\n", + size_t(bnum), loc.x, loc.y, loc.sub_tile, i, j, k); + error++; + } + ++usage_check; + bdone[bnum]++; + } + if (usage_check != place_ctx.grid_blocks[i][j].usage) { + VTR_LOG_ERROR( + "Location (%zu,%zu) usage is %d, but has actual usage %d.\n", + i, j, place_ctx.grid_blocks[i][j].usage, usage_check); + error++; + } + } + + /* Check that every block exists in the device_ctx.grid and cluster_ctx.blocks arrays somewhere. */ + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) + if (bdone[blk_id] != 1) { + VTR_LOG_ERROR("Block %zu listed %d times in data structures.\n", + size_t(blk_id), bdone[blk_id]); + error++; + } + + return error; } int check_macro_placement_consistency() { - int error = 0; - auto& place_ctx = g_vpr_ctx.placement(); - - auto& pl_macros = place_ctx.pl_macros; - - /* Check the pl_macro placement are legal - blocks are in the proper relative position. */ - for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); imacro++) { - auto head_iblk = pl_macros[imacro].members[0].blk_index; - - for (size_t imember = 0; imember < pl_macros[imacro].members.size(); imember++) { - auto member_iblk = pl_macros[imacro].members[imember].blk_index; - - // Compute the suppossed member's x,y,z location - t_pl_loc member_pos = place_ctx.block_locs[head_iblk].loc + pl_macros[imacro].members[imember].offset; - - // Check the place_ctx.block_locs data structure first - if (place_ctx.block_locs[member_iblk].loc != member_pos) { - VTR_LOG_ERROR("Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", - size_t(member_iblk), imacro); - error++; - } - - // Then check the place_ctx.grid data structure - if (place_ctx.grid_blocks[member_pos.x][member_pos.y].blocks[member_pos.sub_tile] != member_iblk) { - VTR_LOG_ERROR("Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", - size_t(member_iblk), imacro); - error++; - } - } // Finish going through all the members - } // Finish going through all the macros - return error; + int error = 0; + auto &place_ctx = g_vpr_ctx.placement(); + + auto &pl_macros = place_ctx.pl_macros; + + /* Check the pl_macro placement are legal - blocks are in the proper relative position. */ + for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); imacro++) { + auto head_iblk = pl_macros[imacro].members[0].blk_index; + + for (size_t imember = 0; imember < pl_macros[imacro].members.size(); + imember++) { + auto member_iblk = pl_macros[imacro].members[imember].blk_index; + + // Compute the suppossed member's x,y,z location + t_pl_loc member_pos = place_ctx.block_locs[head_iblk].loc + + pl_macros[imacro].members[imember].offset; + + // Check the place_ctx.block_locs data structure first + if (place_ctx.block_locs[member_iblk].loc != member_pos) { + VTR_LOG_ERROR( + "Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", + size_t(member_iblk), imacro); + error++; + } + + // Then check the place_ctx.grid data structure + if (place_ctx.grid_blocks[member_pos.x][member_pos.y].blocks[member_pos.sub_tile] + != member_iblk) { + VTR_LOG_ERROR( + "Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", + size_t(member_iblk), imacro); + error++; + } + } // Finish going through all the members + } // Finish going through all the macros + return error; } #ifdef VERBOSE @@ -2807,22 +2835,26 @@ static void print_clb_placement(const char* fname) { #endif static void free_try_swap_arrays() { - g_vpr_ctx.mutable_placement().compressed_block_grids.clear(); + g_vpr_ctx.mutable_placement().compressed_block_grids.clear(); } -static void generate_post_place_timing_reports(const t_placer_opts& placer_opts, - const t_analysis_opts& analysis_opts, - const SetupTimingInfo& timing_info, - const PlacementDelayCalculator& delay_calc) { - auto& timing_ctx = g_vpr_ctx.timing(); - auto& atom_ctx = g_vpr_ctx.atom(); +static void generate_post_place_timing_reports(const t_placer_opts &placer_opts, + const t_analysis_opts &analysis_opts, + const SetupTimingInfo &timing_info, + const PlacementDelayCalculator &delay_calc) { + auto &timing_ctx = g_vpr_ctx.timing(); + auto &atom_ctx = g_vpr_ctx.atom(); - VprTimingGraphResolver resolver(atom_ctx.nlist, atom_ctx.lookup, *timing_ctx.graph, delay_calc); - resolver.set_detail_level(analysis_opts.timing_report_detail); + VprTimingGraphResolver resolver(atom_ctx.nlist, atom_ctx.lookup, + *timing_ctx.graph, delay_calc); + resolver.set_detail_level(analysis_opts.timing_report_detail); - tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, *timing_ctx.constraints); + tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, + *timing_ctx.constraints); - timing_reporter.report_timing_setup(placer_opts.post_place_timing_report_file, *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths); + timing_reporter.report_timing_setup( + placer_opts.post_place_timing_report_file, + *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths); } #if 0 @@ -2837,149 +2869,153 @@ static void update_screen_debug() { #endif static void print_place_status_header() { - VTR_LOG("---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); - VTR_LOG("Tnum Time T Av Cost Av BB Cost Av TD Cost CPD sTNS sWNS Ac Rate Std Dev R lim Crit Exp Tot Moves Alpha\n"); - VTR_LOG(" (sec) (ns) (ns) (ns) \n"); - VTR_LOG("---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); + VTR_LOG( + "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); + VTR_LOG( + "Tnum Time T Av Cost Av BB Cost Av TD Cost CPD sTNS sWNS Ac Rate Std Dev R lim Crit Exp Tot Moves Alpha\n"); + VTR_LOG( + " (sec) (ns) (ns) (ns) \n"); + VTR_LOG( + "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); } -static void print_place_status(const t_annealing_state& state, - const t_placer_statistics& stats, - float elapsed_sec, - float cpd, - float sTNS, - float sWNS, - size_t tot_moves) { - VTR_LOG( - "%4zu " - "%6.1f " - "%7.1e " - "%7.3f %10.2f %-10.5g " - "%7.3f % 10.3g % 8.3f " - "%7.3f %7.4f %6.1f %8.2f", - state.num_temps, - elapsed_sec, - state.t, - stats.av_cost, stats.av_bb_cost, stats.av_timing_cost, - 1e9 * cpd, 1e9 * sTNS, 1e9 * sWNS, - stats.success_rate, stats.std_dev, state.rlim, state.crit_exponent); - - pretty_print_uint(" ", tot_moves, 9, 3); - - VTR_LOG(" %6.3f\n", state.alpha); - fflush(stdout); +static void print_place_status(const t_annealing_state &state, + const t_placer_statistics &stats, float elapsed_sec, float cpd, + float sTNS, float sWNS, size_t tot_moves) { + VTR_LOG("%4zu " + "%6.1f " + "%7.1e " + "%7.3f %10.2f %-10.5g " + "%7.3f % 10.3g % 8.3f " + "%7.3f %7.4f %6.1f %8.2f", state.num_temps, elapsed_sec, state.t, + stats.av_cost, stats.av_bb_cost, stats.av_timing_cost, 1e9 * cpd, + 1e9 * sTNS, 1e9 * sWNS, stats.success_rate, stats.std_dev, + state.rlim, state.crit_exponent); + + pretty_print_uint(" ", tot_moves, 9, 3); + + VTR_LOG(" %6.3f\n", state.alpha); + fflush(stdout); } static void print_resources_utilization() { - auto& place_ctx = g_vpr_ctx.placement(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& device_ctx = g_vpr_ctx.device(); - - int max_block_name = 0; - int max_tile_name = 0; - - //Record the resource requirement - std::map num_type_instances; - std::map> num_placed_instances; - for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { - auto block_loc = place_ctx.block_locs[blk_id]; - auto loc = block_loc.loc; - - auto physical_tile = device_ctx.grid[loc.x][loc.y].type; - auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id); - - num_type_instances[logical_block]++; - num_placed_instances[logical_block][physical_tile]++; - - max_block_name = std::max(max_block_name, strlen(logical_block->name)); - max_tile_name = std::max(max_tile_name, strlen(physical_tile->name)); - } - - VTR_LOG("\n"); - VTR_LOG("Placement resource usage:\n"); - for (auto logical_block : num_type_instances) { - for (auto physical_tile : num_placed_instances[logical_block.first]) { - VTR_LOG(" %-*s implemented as %-*s: %d\n", max_block_name, logical_block.first->name, max_tile_name, physical_tile.first->name, physical_tile.second); - } - } - VTR_LOG("\n"); -} - -static void print_placement_swaps_stats(const t_annealing_state& state) { - size_t total_swap_attempts = num_swap_rejected + num_swap_accepted + num_swap_aborted; - VTR_ASSERT(total_swap_attempts > 0); - - size_t num_swap_print_digits = ceil(log10(total_swap_attempts)); - float reject_rate = (float)num_swap_rejected / total_swap_attempts; - float accept_rate = (float)num_swap_accepted / total_swap_attempts; - float abort_rate = (float)num_swap_aborted / total_swap_attempts; - VTR_LOG("Placement number of temperatures: %d\n", state.num_temps); - VTR_LOG("Placement total # of swap attempts: %*d\n", num_swap_print_digits, total_swap_attempts); - VTR_LOG("\tSwaps accepted: %*d (%4.1f %%)\n", num_swap_print_digits, num_swap_accepted, 100 * accept_rate); - VTR_LOG("\tSwaps rejected: %*d (%4.1f %%)\n", num_swap_print_digits, num_swap_rejected, 100 * reject_rate); - VTR_LOG("\tSwaps aborted : %*d (%4.1f %%)\n", num_swap_print_digits, num_swap_aborted, 100 * abort_rate); + auto &place_ctx = g_vpr_ctx.placement(); + auto &cluster_ctx = g_vpr_ctx.clustering(); + auto &device_ctx = g_vpr_ctx.device(); + + int max_block_name = 0; + int max_tile_name = 0; + + //Record the resource requirement + std::map num_type_instances; + std::map> num_placed_instances; + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + auto block_loc = place_ctx.block_locs[blk_id]; + auto loc = block_loc.loc; + + auto physical_tile = device_ctx.grid[loc.x][loc.y].type; + auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id); + + num_type_instances[logical_block]++; + num_placed_instances[logical_block][physical_tile]++; + + max_block_name = std::max(max_block_name, + strlen(logical_block->name)); + max_tile_name = std::max(max_tile_name, + strlen(physical_tile->name)); + } + + VTR_LOG("\n"); + VTR_LOG("Placement resource usage:\n"); + for (auto logical_block : num_type_instances) { + for (auto physical_tile : num_placed_instances[logical_block.first]) { + VTR_LOG(" %-*s implemented as %-*s: %d\n", max_block_name, + logical_block.first->name, max_tile_name, + physical_tile.first->name, physical_tile.second); + } + } + VTR_LOG("\n"); } -static void print_placement_move_types_stats(const MoveTypeStat& move_type_stat) { - float moves, accepted, rejected, aborted; - float total_moves = std::accumulate(move_type_stat.num_moves.begin(), move_type_stat.num_moves.end(), 0.0); - - std::string move_name; - VTR_LOG("\n\nPercentage of different move types:\n"); - - for (size_t i = 0; i < move_type_stat.num_moves.size(); i++) { - moves = move_type_stat.num_moves[i]; - if (moves != 0) { - accepted = move_type_stat.accepted_moves[i]; - aborted = move_type_stat.aborted_moves[i]; - rejected = moves - (accepted + aborted); - move_name = move_type_to_string(e_move_type(i)); - VTR_LOG("\t%.17s move: %2.2f %% (acc=%2.2f %%, rej=%2.2f %%, aborted=%2.2f %%)\n", move_name.c_str(), 100 * moves / total_moves, 100 * accepted / moves, 100 * rejected / moves, 100 * aborted / moves); - } - } - VTR_LOG("\n"); -} - -static void calculate_reward_and_process_outcome(const t_placer_opts& placer_opts, const MoveOutcomeStats& move_outcome_stats, const double& delta_c, float timing_bb_factor, MoveGenerator& move_generator) { - std::string reward_fun_string = placer_opts.place_reward_fun; - e_reward_function reward_fun = string_to_reward(reward_fun_string); - - if (reward_fun == BASIC) { - move_generator.process_outcome(-1 * delta_c, reward_fun); - } else if (reward_fun == NON_PENALIZING_BASIC || reward_fun == RUNTIME_AWARE) { - if (delta_c < 0) { - move_generator.process_outcome(-1 * delta_c, reward_fun); - } else { - move_generator.process_outcome(0, reward_fun); - } - } else if (reward_fun == WL_BIASED_RUNTIME_AWARE) { - if (delta_c < 0) { - float reward = -1 * (move_outcome_stats.delta_cost_norm + (0.5 - timing_bb_factor) * move_outcome_stats.delta_timing_cost_norm + timing_bb_factor * move_outcome_stats.delta_bb_cost_norm); - move_generator.process_outcome(reward, reward_fun); - } else { - move_generator.process_outcome(0, reward_fun); - } - } +static void print_placement_swaps_stats(const t_annealing_state &state) { + size_t total_swap_attempts = num_swap_rejected + num_swap_accepted + + num_swap_aborted; + VTR_ASSERT(total_swap_attempts > 0); + + size_t num_swap_print_digits = ceil(log10(total_swap_attempts)); + float reject_rate = (float) num_swap_rejected / total_swap_attempts; + float accept_rate = (float) num_swap_accepted / total_swap_attempts; + float abort_rate = (float) num_swap_aborted / total_swap_attempts; + VTR_LOG("Placement number of temperatures: %d\n", state.num_temps); + VTR_LOG("Placement total # of swap attempts: %*d\n", num_swap_print_digits, + total_swap_attempts); + VTR_LOG("\tSwaps accepted: %*d (%4.1f %%)\n", num_swap_print_digits, + num_swap_accepted, 100 * accept_rate); + VTR_LOG("\tSwaps rejected: %*d (%4.1f %%)\n", num_swap_print_digits, + num_swap_rejected, 100 * reject_rate); + VTR_LOG("\tSwaps aborted : %*d (%4.1f %%)\n", num_swap_print_digits, + num_swap_aborted, 100 * abort_rate); } -bool placer_needs_lookahead(const t_vpr_setup& vpr_setup) { - return (vpr_setup.PlacerOpts.place_algorithm.is_timing_driven()); +static void print_placement_move_types_stats( + const MoveTypeStat &move_type_stat) { + float moves, accepted, rejected, aborted; + float total_moves = std::accumulate(move_type_stat.num_moves.begin(), + move_type_stat.num_moves.end(), 0.0); + + std::string move_name; + VTR_LOG("\n\nPercentage of different move types:\n"); + + for (size_t i = 0; i < move_type_stat.num_moves.size(); i++) { + moves = move_type_stat.num_moves[i]; + if (moves != 0) { + accepted = move_type_stat.accepted_moves[i]; + aborted = move_type_stat.aborted_moves[i]; + rejected = moves - (accepted + aborted); + move_name = move_type_to_string(e_move_type(i)); + VTR_LOG( + "\t%.17s move: %2.2f %% (acc=%2.2f %%, rej=%2.2f %%, aborted=%2.2f %%)\n", + move_name.c_str(), 100 * moves / total_moves, + 100 * accepted / moves, 100 * rejected / moves, + 100 * aborted / moves); + } + } + VTR_LOG("\n"); } -void manual_move_info_from_user_and_open_window(ManualMovesInfo* manual_move_info) { - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); +static void calculate_reward_and_process_outcome( + const t_placer_opts &placer_opts, + const MoveOutcomeStats &move_outcome_stats, const double &delta_c, + float timing_bb_factor, MoveGenerator &move_generator) { + std::string reward_fun_string = placer_opts.place_reward_fun; + e_reward_function reward_fun = string_to_reward(reward_fun_string); + + if (reward_fun == BASIC) { + move_generator.process_outcome(-1 * delta_c, reward_fun); + } else if (reward_fun == NON_PENALIZING_BASIC + || reward_fun == RUNTIME_AWARE) { + if (delta_c < 0) { + move_generator.process_outcome(-1 * delta_c, reward_fun); + } else { + move_generator.process_outcome(0, reward_fun); + } + } else if (reward_fun == WL_BIASED_RUNTIME_AWARE) { + if (delta_c < 0) { + float reward = -1 + * (move_outcome_stats.delta_cost_norm + + (0.5 - timing_bb_factor) + * move_outcome_stats.delta_timing_cost_norm + + timing_bb_factor + * move_outcome_stats.delta_bb_cost_norm); + move_generator.process_outcome(reward, reward_fun); + } else { + move_generator.process_outcome(0, reward_fun); + } + } } -void update_manual_move_cost_and_open_window(ManualMovesInfo* manual_move_info, e_move_result& move_outcome, double delta_c, double delta_bb, double delta_t) { - manual_move_info->delta_cost = delta_c; - manual_move_info->delta_bounding_box = delta_bb; - manual_move_info->delta_timing = delta_t; - manual_move_info->placer_move_outcome = move_outcome; - cost_summary(); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - move_outcome = manual_move_info->user_move_outcome; - - //Have to add user placement outcome after if move is accepted +bool placer_needs_lookahead(const t_vpr_setup &vpr_setup) { + return (vpr_setup.PlacerOpts.place_algorithm.is_timing_driven()); } diff --git a/vpr/src/place/place.h b/vpr/src/place/place.h index c56c4ab6d34..d5f7ce71d27 100644 --- a/vpr/src/place/place.h +++ b/vpr/src/place/place.h @@ -3,6 +3,7 @@ #include "vpr_types.h" #include "manual_moves.h" + void try_place(const t_placer_opts& placer_opts, t_annealing_sched annealing_sched, const t_router_opts& router_opts, @@ -14,7 +15,5 @@ void try_place(const t_placer_opts& placer_opts, int num_directs); bool placer_needs_lookahead(const t_vpr_setup& vpr_setup); -void manual_move_info_from_user_and_open_window(ManualMovesInfo* manual_move_info); -//void update_manual_move_cost_and_open_window(ManualMovesInfo* manual_move_info, e_move_result& move_outcome, double delta_c, double delta_bb, double delta_t); #endif From 591c47759d400f779dc21367515171d5151b1dc9 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 23 Jun 2021 13:09:10 -0400 Subject: [PATCH 05/46] Checking if the move genrator handles DSP and RAM block movements --- vpr/main.ui | 20 ----------------- vpr/src/draw/draw.cpp | 31 -------------------------- vpr/src/draw/draw.h | 3 --- vpr/src/draw/manual_moves.cpp | 41 ++++++++++++++++++----------------- vpr/src/draw/manual_moves.h | 1 + vpr/src/place/move_utils.h | 19 ---------------- 6 files changed, 22 insertions(+), 93 deletions(-) diff --git a/vpr/main.ui b/vpr/main.ui index 0e869208013..1a9bb181d0e 100644 --- a/vpr/main.ui +++ b/vpr/main.ui @@ -230,26 +230,6 @@ 1 - - - - Manual Move True - True - False - 0 - False - True - - - 0 - 3 - 1 - 1 - - - - - Clip Routing Util diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 7a82c7acbe5..dd6c7808dd1 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -197,17 +197,9 @@ static void set_block_text(GtkWidget *widget, gint /*response_id*/, gpointer /*data*/); static void clip_routing_util(GtkWidget *widget, gint /*response_id*/, gpointer /*data*/); -static void manual_moves_callback(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/, ezgl::application *app); static void run_graphics_commands(std::string commands); -<<<<<<< HEAD -======= -//Manual moves generator functions -void manual_move_generator_window(); -void move_generator_button_callback(GtkWidget* /*widget*/, GtkWidget* grid); ->>>>>>> 69d872953e314b4bc008b304a5aa8f7e510b6a86 /************************** File Scope Variables ****************************/ //The arrow head position for turning/straight-thru connections in a switch box @@ -215,14 +207,6 @@ constexpr float SB_EDGE_TURN_ARROW_POSITION = 0.2; constexpr float SB_EDGE_STRAIGHT_ARROW_POSITION = 0.95; constexpr float EMPTY_BLOCK_LIGHTEN_FACTOR = 0.20; -//struct that contains information about manual moves for drawing -struct ManualMovesGlobal { - manual_move_info draw_manual_move_info; - GtkWidget* manual_move_window; - //Considering adding more informtion if needed***** -}; - - //Kelly's maximum contrast colors are selected to be easily distinguishable as described in: // Kenneth Kelly, "Twenty-Two Colors of Maximum Contrast", Color Eng. 3(6), 1943 @@ -4570,16 +4554,6 @@ static void setup_default_ezgl_callbacks(ezgl::application *app) { GObject *debugger = app->get_object("debugButton"); g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); -<<<<<<< HEAD -======= - // Connect Debug Button - GObject* debugger = app->get_object("debugButton"); - g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); - - //Manual Moves Button - GObject* manual_moves = app->get_object("manualMove"); - g_signal_connect(manual_moves, "toggled", G_CALLBACK(move_generator_button_callback), app); ->>>>>>> 69d872953e314b4bc008b304a5aa8f7e510b6a86 } // Callback function for Block Outline checkbox @@ -4647,11 +4621,6 @@ void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, application.refresh_drawing(); } -bool get_manual_move_flag() { - GObject *manual_moves = application.get_object("manualMove"); - return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); -} - static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { t_draw_state *draw_state = get_draw_state_vars(); diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index c0abc79a354..ebe90441955 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -103,9 +103,6 @@ void clear_colored_locations(); // otherwise, the function returns false (the location isn't among the highlighted locations) bool highlight_loc_with_specific_color(int x, int y, ezgl::color& loc_color); -//Returns if the option for manual moves has been activated or not. Useful for place.cpp file. -bool get_manual_move_flag(); - #endif /* NO_GRAPHICS */ #endif /* DRAW_H */ diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index cb8222ae284..dc0bcac03cf 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -41,16 +41,16 @@ void draw_manual_moves_window(std::string block_id) { GtkWidget *calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); //Add all to grid - gtk_grid_attach((GtkGrid*) grid, block_label, 0, 0, 1, 1); - gtk_grid_attach((GtkGrid*) grid, block_entry, 0, 1, 1, 1); - gtk_grid_attach((GtkGrid*) grid, to_label, 2, 0, 1, 1); - gtk_grid_attach((GtkGrid*) grid, x, 1, 1, 1, 1); - gtk_grid_attach((GtkGrid*) grid, x_position_entry, 2, 1, 1, 1); - gtk_grid_attach((GtkGrid*) grid, y, 1, 2, 1, 1); - gtk_grid_attach((GtkGrid*) grid, y_position_entry, 2, 2, 1, 1); - gtk_grid_attach((GtkGrid*) grid, subtile, 1, 3, 1, 1); - gtk_grid_attach((GtkGrid*) grid, subtile_position_entry, 2, 3, 1, 1); - gtk_grid_attach((GtkGrid*) grid, calculate_cost_button, 0, 4, 3, 1); //spans three columns + gtk_grid_attach((GtkGrid*)grid, block_label, 0, 0, 1, 1); + gtk_grid_attach((GtkGrid*)grid, block_entry, 0, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, to_label, 2, 0, 1, 1); + gtk_grid_attach((GtkGrid*)grid, x, 1, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, x_position_entry, 2, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, y, 1, 2, 1, 1); + gtk_grid_attach((GtkGrid*)grid, y_position_entry, 2, 2, 1, 1); + gtk_grid_attach((GtkGrid*)grid, subtile, 1, 3, 1, 1); + gtk_grid_attach((GtkGrid*)grid, subtile_position_entry, 2, 3, 1, 1); + gtk_grid_attach((GtkGrid*)grid, calculate_cost_button, 0, 4, 3, 1); //spans three columns //Set margins gtk_widget_set_margin_bottom(grid, 20); @@ -73,7 +73,7 @@ void draw_manual_moves_window(std::string block_id) { } } -void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget *grid) { +void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { int block_id; int x_location; @@ -92,9 +92,7 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget *grid) { if (string_is_a_number(block_id_string)) { //for block ID block_id = std::atoi(block_id_string.c_str()); } else { //for block name - block_id = size_t( - cluster_ctx.clb_nlist.find_block( - gtk_entry_get_text((GtkEntry*) block_entry))); + block_id = size_t(cluster_ctx.clb_nlist.find_block(gtk_entry_get_text((GtkEntry*) block_entry))); } //if the block is not found if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { @@ -104,8 +102,7 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget *grid) { GtkWidget *x_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 1); GtkWidget *y_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 2); - GtkWidget *subtile_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, - 2, 3); + GtkWidget *subtile_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 3); x_location = std::atoi(gtk_entry_get_text((GtkEntry*) x_position_entry)); y_location = std::atoi(gtk_entry_get_text((GtkEntry*) y_position_entry)); @@ -119,10 +116,8 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget *grid) { //If the block requested is already in that location. ClusterBlockId current_block = ClusterBlockId(block_id); t_pl_loc current_block_loc = place_ctx.block_locs[current_block].loc; - if (x_location == current_block_loc.x && y_location == current_block_loc.y - && subtile_location == current_block_loc.sub_tile) { - invalid_breakpoint_entry_window( - "The block is currently in this location"); + if (x_location == current_block_loc.x && y_location == current_block_loc.y && subtile_location == current_block_loc.sub_tile) { + invalid_breakpoint_entry_window("The block is currently in this location"); valid_input = false; } //Checks if all fields from the user input window are complete. @@ -162,10 +157,16 @@ bool string_is_a_number(std::string block_id) { return true; } +bool get_manual_move_flag() { + GObject *manual_moves = application.get_object("manualMove"); + return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); +} + ManualMovesGlobals* get_manual_moves_global() { return &manual_moves_global; } + //Manual Move Generator function e_create_move ManualMoveGenerator::propose_move( t_pl_blocks_to_be_moved &blocks_affected, float /*rlim*/) { diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 714c9c20373..df4786ad58d 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -54,6 +54,7 @@ void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); bool string_is_a_number(std::string block_id); +bool get_manual_move_flag(); void cost_summary_dialog(); ManualMovesGlobals* get_manual_moves_global(); void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index 634467610d1..210799f2df3 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -171,25 +171,6 @@ void compressed_grid_to_loc(t_logical_block_type_ptr blk_type, int cx, int cy, t */ bool find_compatible_compressed_loc_in_range(t_logical_block_type_ptr type, int min_cx, int max_cx, int min_cy, int max_cy, int delta_cx, int cx_from, int cy_from, int& cx_to, int& cy_to, bool is_median); -<<<<<<< HEAD std::string e_move_result_to_string(e_move_result move_outcome); -======= -//Manual moves struct: Contains the values needed for a manual move (e.g. block_ID, block_name, x_position, y_position, cost, timing, if input is valid, and if the move is acepted. -struct manual_move_info { - int block_id = -1; - std::string block_name = NULL; - int x_position = -1; - int y_position = -1; - float delta_cost = 0; - float delta_timing = 0; - bool valid_input = true; - e_move_result user_move_outcome = ABORTED; - e_move_result placer_move_outcome = ABORTED; - //considering adding more attributes needed for manual moves****** -}; - - - ->>>>>>> 69d872953e314b4bc008b304a5aa8f7e510b6a86 #endif From 86cc753d450aab2ce533576c967c48e105293b6e Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 23 Jun 2021 14:42:53 -0400 Subject: [PATCH 06/46] Changed the manual move toggle button in layout --- vpr/main.ui | 5 ++--- vpr/src/draw/manual_moves.cpp | 28 ++++++++++++---------------- vpr/src/place/move_utils.cpp | 10 ++++++++-- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/vpr/main.ui b/vpr/main.ui index 1a9bb181d0e..ad1308cc694 100644 --- a/vpr/main.ui +++ b/vpr/main.ui @@ -192,7 +192,7 @@ 1 - + True False @@ -247,7 +247,6 @@ 1 - Manual Move @@ -263,7 +262,7 @@ 1 1 - + diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index dc0bcac03cf..6ae35ac8ad0 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -20,6 +20,7 @@ void draw_manual_moves_window(std::string block_id) { manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position((GtkWindow*) manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); gtk_window_set_title((GtkWindow*) manual_moves_global.manual_move_window, "Manual Moves Generator"); + gtk_widget_set_name(manual_moves_global.manual_move_window, "manual_move_window"); GtkWidget *grid = gtk_grid_new(); GtkWidget *block_entry = gtk_entry_new(); @@ -29,16 +30,16 @@ void draw_manual_moves_window(std::string block_id) { manual_moves_global.user_highlighted_block = false; } - GtkWidget *x_position_entry = gtk_entry_new(); - GtkWidget *y_position_entry = gtk_entry_new(); - GtkWidget *subtile_position_entry = gtk_entry_new(); - GtkWidget *block_label = gtk_label_new("Block ID/Block Name:"); - GtkWidget *to_label = gtk_label_new("To Location:"); - GtkWidget *x = gtk_label_new("x:"); - GtkWidget *y = gtk_label_new("y:"); - GtkWidget *subtile = gtk_label_new("Subtile:"); + GtkWidget* x_position_entry = gtk_entry_new(); + GtkWidget* y_position_entry = gtk_entry_new(); + GtkWidget* subtile_position_entry = gtk_entry_new(); + GtkWidget* block_label = gtk_label_new("Block ID/Block Name:"); + GtkWidget* to_label = gtk_label_new("To Location:"); + GtkWidget* x = gtk_label_new("x:"); + GtkWidget* y = gtk_label_new("y:"); + GtkWidget* subtile = gtk_label_new("Subtile:"); - GtkWidget *calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); + GtkWidget* calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); //Add all to grid gtk_grid_attach((GtkGrid*)grid, block_label, 0, 0, 1, 1); @@ -65,8 +66,9 @@ void draw_manual_moves_window(std::string block_id) { gtk_widget_set_halign(calculate_cost_button, GTK_ALIGN_CENTER); //connect signals - g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); + g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); gtk_widget_show_all(manual_moves_global.manual_move_window); @@ -202,12 +204,6 @@ e_create_move ManualMoveGenerator::propose_move( return e_create_move::ABORT; } - /*std::cout << "The to subtile: " << to.sub_tile << std::endl; - for(auto itr = compatible_subtiles.begin(); itr != compatible_subtiles.end(); itr++) { - std::cout << *itr << std::endl; - }*/ - - e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 85429dcc6fd..5946ecd7a27 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -450,12 +450,15 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& device_ctx = g_vpr_ctx.device(); auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.placement(); + + //For manual moves feature GObject* manual_move_toggle = application.get_object("manualMove"); + bool activated = gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle); if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { - if(gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle)) { + if(activated) { invalid_breakpoint_entry_window("Dimensions are out of bounds"); } return false; @@ -466,7 +469,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { - if(gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle)) { + if(activated) { invalid_breakpoint_entry_window("Blocks are not compatible"); } return false; @@ -475,6 +478,9 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { if (place_ctx.block_locs[b_to].is_fixed) { + if(activated) { + invalid_breakpoint_entry_window("Block is fixed"); + } return false; } } From 5dc28a82971cd87f785531ee3d8ddc6617720939 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 23 Jun 2021 15:26:43 -0400 Subject: [PATCH 07/46] Fixed gtk errors and changed the size of the button --- vpr/src/draw/buttons.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/draw/buttons.cpp b/vpr/src/draw/buttons.cpp index a6bc64829f7..9773463b420 100644 --- a/vpr/src/draw/buttons.cpp +++ b/vpr/src/draw/buttons.cpp @@ -22,7 +22,7 @@ //location of spin buttons, combo boxes, and labels on grid gint box_width = 1; -gint box_height = 0.5; +gint box_height = 1; gint label_left_start_col = 0; gint box_left_start_col = 0; gint button_row = 2; // 2 is the row num of the window button in main.ui, add buttons starting from this row From 19be5b317b4847f3bdfc74f130418ba7abc6c4b0 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 28 Jun 2021 14:58:55 -0400 Subject: [PATCH 08/46] Reduced number of calls to manual move toggle button, to reduce runtime. --- vpr/src/draw/draw.cpp | 7 ++++--- vpr/src/draw/manual_moves.cpp | 12 +++++------ vpr/src/draw/manual_moves.h | 2 +- vpr/src/place/move_utils.cpp | 10 ++++----- vpr/src/place/place.cpp | 39 ++++++++--------------------------- 5 files changed, 24 insertions(+), 46 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index dc94cf175ee..c2709936cb6 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -197,9 +197,11 @@ static void set_block_text(GtkWidget *widget, gint /*response_id*/, gpointer /*data*/); static void clip_routing_util(GtkWidget *widget, gint /*response_id*/, gpointer /*data*/); + static void run_graphics_commands(std::string commands); + /************************** File Scope Variables ****************************/ //The arrow head position for turning/straight-thru connections in a switch box @@ -4433,9 +4435,8 @@ static void highlight_blocks(double x, double y) { //If manual moves is activated, then user can select block from the grid. ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - manual_move_global->user_highlighted_block = true; - if (get_manual_move_flag()) { - if (!manual_move_global->mm_window_is_open) { + if(manual_move_global->manual_move_enabled) { + if(!manual_move_global->mm_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 6ae35ac8ad0..9910b770736 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -25,11 +25,7 @@ void draw_manual_moves_window(std::string block_id) { GtkWidget *grid = gtk_grid_new(); GtkWidget *block_entry = gtk_entry_new(); - if (manual_moves_global.user_highlighted_block) { - gtk_entry_set_text((GtkEntry*) block_entry, block_id.c_str()); - manual_moves_global.user_highlighted_block = false; - } - + gtk_entry_set_text((GtkEntry*) block_entry, block_id.c_str()); GtkWidget* x_position_entry = gtk_entry_new(); GtkWidget* y_position_entry = gtk_entry_new(); GtkWidget* subtile_position_entry = gtk_entry_new(); @@ -72,6 +68,7 @@ void draw_manual_moves_window(std::string block_id) { gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); gtk_widget_show_all(manual_moves_global.manual_move_window); + } } @@ -161,10 +158,13 @@ bool string_is_a_number(std::string block_id) { bool get_manual_move_flag() { GObject *manual_moves = application.get_object("manualMove"); - return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); + manual_moves_global.manual_move_enabled = gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); + return manual_moves_global.manual_move_enabled; } ManualMovesGlobals* get_manual_moves_global() { + //Enables manual move flag when toggle button is active + get_manual_move_flag(); return &manual_moves_global; } diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index df4786ad58d..131ed4e21c6 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -38,7 +38,7 @@ struct ManualMovesGlobals { ManualMovesInfo manual_move_info; GtkWidget* manual_move_window; bool mm_window_is_open = false; - bool user_highlighted_block = false; + bool manual_move_enabled = false; }; /** Manual Moves Generator, inherits from MoveGenerator class **/ diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 5946ecd7a27..d56c586d97b 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -452,13 +452,11 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& place_ctx = g_vpr_ctx.placement(); //For manual moves feature - GObject* manual_move_toggle = application.get_object("manualMove"); - bool activated = gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle); - + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { - if(activated) { + if(manual_move_global->manual_move_enabled) { invalid_breakpoint_entry_window("Dimensions are out of bounds"); } return false; @@ -469,7 +467,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { - if(activated) { + if(manual_move_global->manual_move_enabled) { invalid_breakpoint_entry_window("Blocks are not compatible"); } return false; @@ -478,7 +476,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { if (place_ctx.block_locs[b_to].is_fixed) { - if(activated) { + if(manual_move_global->manual_move_enabled) { invalid_breakpoint_entry_window("Block is fixed"); } return false; diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 860e07df856..ccd4a984ebf 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1285,32 +1285,19 @@ static e_move_result try_swap(const t_annealing_state *state, rlim = state->rlim; } -#ifndef NO_GRAPHICS - bool manual_move_flag = false; - manual_move_flag = get_manual_move_flag(); ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + e_create_move create_move_outcome; + - if (manual_move_flag) { + if (manual_move_global->manual_move_enabled) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - } + create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); -#endif /* NO_GRAPHICS */ - - e_create_move create_move_outcome; - - if (manual_move_flag) { - create_move_outcome = manual_move_generator.propose_move( - blocks_affected, rlim); - if (create_move_outcome == e_create_move::VALID) - std::cout << "Propose move: VALID" << std::endl; - else if (create_move_outcome == e_create_move::ABORT) - std::cout << "Propose move: ABORT" << std::endl; } else { //Generate a new move (perturbation) used to explore the space of possible placements - create_move_outcome = move_generator.propose_move(blocks_affected, - move_type, rlim, placer_opts, criticalities); + create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } ++move_type_stat.num_moves[(int) move_type]; @@ -1318,9 +1305,7 @@ static e_move_result try_swap(const t_annealing_state *state, e_move_result move_outcome = ABORTED; - if (create_move_outcome == e_create_move::ABORT - || (manual_move_flag - && !manual_move_global->manual_move_info.valid_input)) { + if (create_move_outcome == e_create_move::ABORT) { LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), "ABORTED", @@ -1399,7 +1384,7 @@ static e_move_result try_swap(const t_annealing_state *state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); - if (manual_move_flag && manual_move_global->manual_move_info.valid_input) { + if (manual_move_global->manual_move_enabled) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); @@ -1442,10 +1427,8 @@ static e_move_result try_swap(const t_annealing_state *state, ++move_type_stat.accepted_moves[(int) move_type]; - //Highlights the new block when manual move is selected. - if (manual_move_flag) { - highlight_block_location(); - } + //Highlights the new block in the new location if the manual move was accepted. + highlight_block_location(); } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); @@ -1516,10 +1499,6 @@ static e_move_result try_swap(const t_annealing_state *state, check_place(*costs, delay_model, place_algorithm); #endif - if (manual_move_flag) { - manual_move_global->manual_move_info.valid_input = true; - } - return move_outcome; } From 2c6f1a63e4c9250a75bc50e4f259a9ad50aa6bf0 Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 29 Jun 2021 10:39:11 -0400 Subject: [PATCH 09/46] Reverting to commit 15174ed55 (version without segmentation faults) --- vpr/src/draw/draw.cpp | 7 +++---- vpr/src/draw/manual_moves.cpp | 12 +++++------ vpr/src/draw/manual_moves.h | 2 +- vpr/src/place/move_utils.cpp | 10 +++++---- vpr/src/place/place.cpp | 39 +++++++++++++++++++++++++++-------- 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index c2709936cb6..dc94cf175ee 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -197,11 +197,9 @@ static void set_block_text(GtkWidget *widget, gint /*response_id*/, gpointer /*data*/); static void clip_routing_util(GtkWidget *widget, gint /*response_id*/, gpointer /*data*/); - static void run_graphics_commands(std::string commands); - /************************** File Scope Variables ****************************/ //The arrow head position for turning/straight-thru connections in a switch box @@ -4435,8 +4433,9 @@ static void highlight_blocks(double x, double y) { //If manual moves is activated, then user can select block from the grid. ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - if(manual_move_global->manual_move_enabled) { - if(!manual_move_global->mm_window_is_open) { + manual_move_global->user_highlighted_block = true; + if (get_manual_move_flag()) { + if (!manual_move_global->mm_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 9910b770736..6ae35ac8ad0 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -25,7 +25,11 @@ void draw_manual_moves_window(std::string block_id) { GtkWidget *grid = gtk_grid_new(); GtkWidget *block_entry = gtk_entry_new(); - gtk_entry_set_text((GtkEntry*) block_entry, block_id.c_str()); + if (manual_moves_global.user_highlighted_block) { + gtk_entry_set_text((GtkEntry*) block_entry, block_id.c_str()); + manual_moves_global.user_highlighted_block = false; + } + GtkWidget* x_position_entry = gtk_entry_new(); GtkWidget* y_position_entry = gtk_entry_new(); GtkWidget* subtile_position_entry = gtk_entry_new(); @@ -68,7 +72,6 @@ void draw_manual_moves_window(std::string block_id) { gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); gtk_widget_show_all(manual_moves_global.manual_move_window); - } } @@ -158,13 +161,10 @@ bool string_is_a_number(std::string block_id) { bool get_manual_move_flag() { GObject *manual_moves = application.get_object("manualMove"); - manual_moves_global.manual_move_enabled = gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); - return manual_moves_global.manual_move_enabled; + return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); } ManualMovesGlobals* get_manual_moves_global() { - //Enables manual move flag when toggle button is active - get_manual_move_flag(); return &manual_moves_global; } diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 131ed4e21c6..df4786ad58d 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -38,7 +38,7 @@ struct ManualMovesGlobals { ManualMovesInfo manual_move_info; GtkWidget* manual_move_window; bool mm_window_is_open = false; - bool manual_move_enabled = false; + bool user_highlighted_block = false; }; /** Manual Moves Generator, inherits from MoveGenerator class **/ diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index d56c586d97b..5946ecd7a27 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -452,11 +452,13 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& place_ctx = g_vpr_ctx.placement(); //For manual moves feature - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + GObject* manual_move_toggle = application.get_object("manualMove"); + bool activated = gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle); + if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { - if(manual_move_global->manual_move_enabled) { + if(activated) { invalid_breakpoint_entry_window("Dimensions are out of bounds"); } return false; @@ -467,7 +469,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { - if(manual_move_global->manual_move_enabled) { + if(activated) { invalid_breakpoint_entry_window("Blocks are not compatible"); } return false; @@ -476,7 +478,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { if (place_ctx.block_locs[b_to].is_fixed) { - if(manual_move_global->manual_move_enabled) { + if(activated) { invalid_breakpoint_entry_window("Block is fixed"); } return false; diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index ccd4a984ebf..860e07df856 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1285,19 +1285,32 @@ static e_move_result try_swap(const t_annealing_state *state, rlim = state->rlim; } +#ifndef NO_GRAPHICS + bool manual_move_flag = false; + manual_move_flag = get_manual_move_flag(); ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - e_create_move create_move_outcome; - - if (manual_move_global->manual_move_enabled) { + if (manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); + } +#endif /* NO_GRAPHICS */ + + e_create_move create_move_outcome; + + if (manual_move_flag) { + create_move_outcome = manual_move_generator.propose_move( + blocks_affected, rlim); + if (create_move_outcome == e_create_move::VALID) + std::cout << "Propose move: VALID" << std::endl; + else if (create_move_outcome == e_create_move::ABORT) + std::cout << "Propose move: ABORT" << std::endl; } else { //Generate a new move (perturbation) used to explore the space of possible placements - create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + create_move_outcome = move_generator.propose_move(blocks_affected, + move_type, rlim, placer_opts, criticalities); } ++move_type_stat.num_moves[(int) move_type]; @@ -1305,7 +1318,9 @@ static e_move_result try_swap(const t_annealing_state *state, e_move_result move_outcome = ABORTED; - if (create_move_outcome == e_create_move::ABORT) { + if (create_move_outcome == e_create_move::ABORT + || (manual_move_flag + && !manual_move_global->manual_move_info.valid_input)) { LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), "ABORTED", @@ -1384,7 +1399,7 @@ static e_move_result try_swap(const t_annealing_state *state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); - if (manual_move_global->manual_move_enabled) { + if (manual_move_flag && manual_move_global->manual_move_info.valid_input) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); @@ -1427,8 +1442,10 @@ static e_move_result try_swap(const t_annealing_state *state, ++move_type_stat.accepted_moves[(int) move_type]; - //Highlights the new block in the new location if the manual move was accepted. - highlight_block_location(); + //Highlights the new block when manual move is selected. + if (manual_move_flag) { + highlight_block_location(); + } } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); @@ -1499,6 +1516,10 @@ static e_move_result try_swap(const t_annealing_state *state, check_place(*costs, delay_model, place_algorithm); #endif + if (manual_move_flag) { + manual_move_global->manual_move_info.valid_input = true; + } + return move_outcome; } From f9f51e692a93c4d465e30a30cc1e8641e101b944 Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 29 Jun 2021 23:15:34 -0400 Subject: [PATCH 10/46] Reduced the amount of manual move enable in try_swap function. No segmentation faults --- vpr/src/draw/manual_moves.cpp | 59 ++++++++++------------------------- vpr/src/draw/manual_moves.h | 3 +- vpr/src/place/move_utils.cpp | 4 +-- vpr/src/place/place.cpp | 43 +++++++------------------ 4 files changed, 29 insertions(+), 80 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 6ae35ac8ad0..15cd9dcb4e2 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -137,7 +137,10 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { manual_moves_global.manual_move_info.to_location = to; //Highlighting the block - highlight_block_location(); + deselect_all(); + ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); + application.refresh_drawing(); //Continues to move costs window. GtkWidget *proceed = find_button("ProceedButton"); @@ -170,8 +173,7 @@ ManualMovesGlobals* get_manual_moves_global() { //Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move( - t_pl_blocks_to_be_moved &blocks_affected, float /*rlim*/) { +e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved &blocks_affected, float /*rlim*/) { int block_id = manual_moves_global.manual_move_info.blockID; t_pl_loc to = manual_moves_global.manual_move_info.to_location; @@ -283,14 +285,17 @@ void cost_summary_dialog() { } -void highlight_block_location() { - auto& cluster_ctx = g_vpr_ctx.clustering(); - //Unselects all blocks first - deselect_all(); - //Highlighting the block - ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); - application.refresh_drawing(); +void highlight_new_block_location(bool manual_move_flag) { + + if(manual_move_flag) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + //Unselects all blocks first + deselect_all(); + //Highlighting the block + ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); + application.refresh_drawing(); + } } //Updates ManualMovesInfo cost members @@ -312,36 +317,4 @@ void deactivating_toggle_button() { gtk_toggle_button_set_active((GtkToggleButton*) manual_move_toggle, FALSE); } -/*void dialog_callback(GtkDialog* dialog, gint response_id, gpointer user_data) { - - //Update message if user accepts the move. - std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); - msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; - - switch(result) { - //If the user accepts the manual move - case GTK_RESPONSE_ACCEPT: - manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; - application.update_message(msg.c_str()); - //close_manual_moves_window(); - break; - //If the user rejects the manual move - case GTK_RESPONSE_REJECT: - manual_moves_global.manual_move_info.user_move_outcome = REJECTED; - application.update_message("Manual move was rejected"); - //close_manual_moves_window(); - break; - default: - manual_moves_global.manual_move_info.user_move_outcome = ABORTED; - break; - - } - - gtk_widget_destroy(GTK_WIDGET(dialog)); - - -}*/ - - - #endif diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index df4786ad58d..1fcf6d91694 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -58,9 +58,8 @@ bool get_manual_move_flag(); void cost_summary_dialog(); ManualMovesGlobals* get_manual_moves_global(); void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); -void highlight_block_location(); +void highlight_new_block_location(bool manual_move_flag); -//void dialog_callback(GtkDialog* dialog, gint response_id, gpointer user_data); void deactivating_toggle_button(); diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 5946ecd7a27..f0e5b14374d 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -452,9 +452,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& place_ctx = g_vpr_ctx.placement(); //For manual moves feature - GObject* manual_move_toggle = application.get_object("manualMove"); - bool activated = gtk_toggle_button_get_active((GtkToggleButton*)manual_move_toggle); - + bool activated = get_manual_move_flag(); if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 860e07df856..5798795ae01 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1285,32 +1285,20 @@ static e_move_result try_swap(const t_annealing_state *state, rlim = state->rlim; } -#ifndef NO_GRAPHICS - - bool manual_move_flag = false; - manual_move_flag = get_manual_move_flag(); + bool manual_move_flag = get_manual_move_flag(); ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - if (manual_move_flag) { + e_create_move create_move_outcome; + + if(manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - } - -#endif /* NO_GRAPHICS */ - - e_create_move create_move_outcome; - if (manual_move_flag) { - create_move_outcome = manual_move_generator.propose_move( - blocks_affected, rlim); - if (create_move_outcome == e_create_move::VALID) - std::cout << "Propose move: VALID" << std::endl; - else if (create_move_outcome == e_create_move::ABORT) - std::cout << "Propose move: ABORT" << std::endl; - } else { + create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); + } + else { //Generate a new move (perturbation) used to explore the space of possible placements - create_move_outcome = move_generator.propose_move(blocks_affected, - move_type, rlim, placer_opts, criticalities); + create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } ++move_type_stat.num_moves[(int) move_type]; @@ -1318,9 +1306,7 @@ static e_move_result try_swap(const t_annealing_state *state, e_move_result move_outcome = ABORTED; - if (create_move_outcome == e_create_move::ABORT - || (manual_move_flag - && !manual_move_global->manual_move_info.valid_input)) { + if (create_move_outcome == e_create_move::ABORT) { LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), "ABORTED", @@ -1399,10 +1385,9 @@ static e_move_result try_swap(const t_annealing_state *state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); - if (manual_move_flag && manual_move_global->manual_move_info.valid_input) { + if (manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); - //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } @@ -1443,9 +1428,7 @@ static e_move_result try_swap(const t_annealing_state *state, ++move_type_stat.accepted_moves[(int) move_type]; //Highlights the new block when manual move is selected. - if (manual_move_flag) { - highlight_block_location(); - } + highlight_new_block_location(manual_move_flag); } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); @@ -1516,10 +1499,6 @@ static e_move_result try_swap(const t_annealing_state *state, check_place(*costs, delay_model, place_algorithm); #endif - if (manual_move_flag) { - manual_move_global->manual_move_info.valid_input = true; - } - return move_outcome; } From ee7545546d5cf971de4938002efd146f0eb30d09 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 7 Jul 2021 15:18:49 -0400 Subject: [PATCH 11/46] Added timer class to analyze code for manual moves. Will delete later --- vpr/src/draw/draw.cpp | 4 ++-- vpr/src/draw/manual_moves.cpp | 3 --- vpr/src/draw/manual_moves.h | 24 ++++++++++++++++++++++++ vpr/src/place/place.cpp | 13 +++++++++---- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index dc94cf175ee..f247c1f4eb6 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -4432,9 +4432,9 @@ static void highlight_blocks(double x, double y) { } //If manual moves is activated, then user can select block from the grid. - ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - manual_move_global->user_highlighted_block = true; if (get_manual_move_flag()) { + ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + manual_move_global->user_highlighted_block = true; if (!manual_move_global->mm_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 15cd9dcb4e2..3af822ee2eb 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -149,7 +149,6 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { } else { manual_moves_global.manual_move_info.valid_input = false; } - } bool string_is_a_number(std::string block_id) { @@ -208,7 +207,6 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved &blocks_ e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; - } void cost_summary_dialog() { @@ -286,7 +284,6 @@ void cost_summary_dialog() { } void highlight_new_block_location(bool manual_move_flag) { - if(manual_move_flag) { auto& cluster_ctx = g_vpr_ctx.clustering(); //Unselects all blocks first diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 1fcf6d91694..314460eb4e0 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -48,6 +48,30 @@ class ManualMoveGenerator: public MoveGenerator { e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/); }; +class Timer { + public: + Timer() { + m_StartTimepoint = std::chrono::high_resolution_clock::now(); + } + ~Timer() { + Stop(); + } + void Stop() { + auto endTimepoint = std::chrono::high_resolution_clock::now(); + + auto start = std::chrono::time_point_cast(m_StartTimepoint).time_since_epoch().count(); + auto end = std::chrono::time_point_cast(endTimepoint).time_since_epoch().count(); + + auto duration = end - start; + double ms = duration * 0.001; + double s = duration * 0.000001; + + std::cout << duration << "us -- " << ms << "ms -- " << s << "s\n"; + } + private: + std::chrono::time_point m_StartTimepoint; +}; + /** manual moves functions **/ void draw_manual_moves_window(std::string block_id); diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 5798795ae01..14bff8e2f75 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "vtr_assert.h" #include "vtr_log.h" @@ -1286,15 +1287,16 @@ static e_move_result try_swap(const t_annealing_state *state, } bool manual_move_flag = get_manual_move_flag(); - ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + e_create_move create_move_outcome; + if(manual_move_flag) { - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); + create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); } else { //Generate a new move (perturbation) used to explore the space of possible placements @@ -1386,12 +1388,15 @@ static e_move_result try_swap(const t_annealing_state *state, move_outcome = assess_swap(delta_c, state->t); if (manual_move_flag) { + ManualMovesGlobals *manual_move_global = get_manual_moves_global(); update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); + //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } + if (move_outcome == ACCEPTED) { costs->cost += delta_c; costs->bb_cost += bb_delta_c; From c930caf328544ce831c1900fd2f4e421d3220944 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 12 Jul 2021 20:35:19 -0400 Subject: [PATCH 12/46] Reduced the timing in manual moves in place.cpp by changing the manual move flag. Timing is now similar to master branch --- vpr/src/draw/draw.cpp | 4 ++-- vpr/src/draw/manual_moves.cpp | 6 ++++-- vpr/src/draw/manual_moves.h | 4 +++- vpr/src/place/move_utils.cpp | 8 ++++---- vpr/src/place/place.cpp | 23 ++++++++++++----------- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index f247c1f4eb6..0f92cf2b57d 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -4432,8 +4432,8 @@ static void highlight_blocks(double x, double y) { } //If manual moves is activated, then user can select block from the grid. - if (get_manual_move_flag()) { - ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + if (manual_move_global->manual_move_flag) { manual_move_global->user_highlighted_block = true; if (!manual_move_global->mm_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 3af822ee2eb..1750d3fb3b2 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -161,9 +161,11 @@ bool string_is_a_number(std::string block_id) { return true; } -bool get_manual_move_flag() { +void get_manual_move_flag() { GObject *manual_moves = application.get_object("manualMove"); - return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); + //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); + manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); + //return manual_moves_global.manual_move_flag; } ManualMovesGlobals* get_manual_moves_global() { diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 314460eb4e0..062707b80c5 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -39,6 +39,7 @@ struct ManualMovesGlobals { GtkWidget* manual_move_window; bool mm_window_is_open = false; bool user_highlighted_block = false; + bool manual_move_flag = false; }; /** Manual Moves Generator, inherits from MoveGenerator class **/ @@ -78,7 +79,8 @@ void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); bool string_is_a_number(std::string block_id); -bool get_manual_move_flag(); +//bool get_manual_move_flag(); +void get_manual_move_flag(); void cost_summary_dialog(); ManualMovesGlobals* get_manual_moves_global(); void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index f0e5b14374d..8dbe4523aff 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -452,11 +452,11 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& place_ctx = g_vpr_ctx.placement(); //For manual moves feature - bool activated = get_manual_move_flag(); + ManualMovesGlobals *manual_move_global = get_manual_moves_global(); if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { - if(activated) { + if(manual_move_global->manual_move_flag) { invalid_breakpoint_entry_window("Dimensions are out of bounds"); } return false; @@ -467,7 +467,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { - if(activated) { + if(manual_move_global->manual_move_flag) { invalid_breakpoint_entry_window("Blocks are not compatible"); } return false; @@ -476,7 +476,7 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { if (place_ctx.block_locs[b_to].is_fixed) { - if(activated) { + if(manual_move_global->manual_move_flag) { invalid_breakpoint_entry_window("Block is fixed"); } return false; diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 14bff8e2f75..a195df0377e 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1152,7 +1152,12 @@ static float starting_t(const t_annealing_state *state, t_placer_costs *costs, int move_lim = std::min(state->move_lim_max, (int) cluster_ctx.clb_nlist.blocks().size()); + for (int i = 0; i < move_lim; i++) { + + //Checks manual move flag for manual move feature + get_manual_move_flag(); + //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack e_move_result swap_result = try_swap(state, costs, move_generator, manual_move_generator, timing_info, pin_timing_invalidator, @@ -1286,17 +1291,15 @@ static e_move_result try_swap(const t_annealing_state *state, rlim = state->rlim; } - bool manual_move_flag = get_manual_move_flag(); - + ManualMovesGlobals *manual_move_global = get_manual_moves_global(); e_create_move create_move_outcome; + if(manual_move_global->manual_move_flag) { + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - if(manual_move_flag) { - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - - create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); + create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); } else { //Generate a new move (perturbation) used to explore the space of possible placements @@ -1387,8 +1390,7 @@ static e_move_result try_swap(const t_annealing_state *state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); - if (manual_move_flag) { - ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); @@ -1396,7 +1398,6 @@ static e_move_result try_swap(const t_annealing_state *state, move_outcome = manual_move_global->manual_move_info.user_move_outcome; } - if (move_outcome == ACCEPTED) { costs->cost += delta_c; costs->bb_cost += bb_delta_c; @@ -1433,7 +1434,7 @@ static e_move_result try_swap(const t_annealing_state *state, ++move_type_stat.accepted_moves[(int) move_type]; //Highlights the new block when manual move is selected. - highlight_new_block_location(manual_move_flag); + highlight_new_block_location(manual_move_global->manual_move_flag); } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); From 38e13712e9121a6ed60444e375f808ad393d4309 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 12 Jul 2021 20:53:13 -0400 Subject: [PATCH 13/46] Used make format to format code --- vpr/src/draw/draw.cpp | 6031 +++++++++++++-------------- vpr/src/draw/manual_moves.cpp | 530 ++- vpr/src/draw/manual_moves.h | 86 +- vpr/src/place/move_utils.cpp | 24 +- vpr/src/place/move_utils.h | 1 - vpr/src/place/place.cpp | 4472 ++++++++++---------- vpr/src/place/placer_breakpoint.cpp | 1 - 7 files changed, 5544 insertions(+), 5601 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 0f92cf2b57d..5adc801b60c 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -86,120 +86,107 @@ //#define TIME_DRAWSCREEN /* Enable if want to track runtime for drawscreen() */ /********************** Subroutines local to this module ********************/ -static void drawplace(ezgl::renderer *g); -static void drawnets(ezgl::renderer *g); -static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer *g); -static void draw_congestion(ezgl::renderer *g); -static void draw_routing_costs(ezgl::renderer *g); -static void draw_routing_bb(ezgl::renderer *g); -static void draw_routing_util(ezgl::renderer *g); -static void draw_crit_path(ezgl::renderer *g); -static void draw_placement_macros(ezgl::renderer *g); - -void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, - char *key_name); -void act_on_mouse_press(ezgl::application *app, GdkEventButton *event, double x, - double y); -void act_on_mouse_move(ezgl::application *app, GdkEventButton *event, double x, - double y); - -static void draw_routed_net(ClusterNetId net, ezgl::renderer *g); -void draw_partial_route(const std::vector &rr_nodes_to_draw, - ezgl::renderer *g); -static void draw_rr(ezgl::renderer *g); -static void draw_rr_edges(int from_node, ezgl::renderer *g); -static void draw_rr_pin(int inode, const ezgl::color &color, ezgl::renderer *g); -static void draw_rr_chan(int inode, const ezgl::color color, ezgl::renderer *g); -static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer *g); -static void draw_pin_to_chan_edge(int pin_node, int chan_node, - ezgl::renderer *g); -static void draw_get_rr_src_sink_coords(const t_rr_node &node, float *xcen, - float *ycen); -static void draw_x(float x, float y, float size, ezgl::renderer *g); -static void draw_pin_to_pin(int opin, int ipin, ezgl::renderer *g); -static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer *g); -static void draw_source_to_pin(int source_node, int opin_node, - ezgl::renderer *g); -static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, - bool buffered, bool switch_configurable, ezgl::renderer *g); -static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, - short switch_type, ezgl::renderer *g); -static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, - short switch_type, ezgl::renderer *g); -static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, - int chany_node, int chany_track, enum e_edge_dir edge_dir, - short switch_type, ezgl::renderer *g); -static int get_track_num(int inode, const vtr::OffsetMatrix &chanx_track, - const vtr::OffsetMatrix &chany_track); +static void drawplace(ezgl::renderer* g); +static void drawnets(ezgl::renderer* g); +static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer* g); +static void draw_congestion(ezgl::renderer* g); +static void draw_routing_costs(ezgl::renderer* g); +static void draw_routing_bb(ezgl::renderer* g); +static void draw_routing_util(ezgl::renderer* g); +static void draw_crit_path(ezgl::renderer* g); +static void draw_placement_macros(ezgl::renderer* g); + +void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* key_name); +void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, double y); +void act_on_mouse_move(ezgl::application* app, GdkEventButton* event, double x, double y); + +static void draw_routed_net(ClusterNetId net, ezgl::renderer* g); +void draw_partial_route(const std::vector& rr_nodes_to_draw, + ezgl::renderer* g); +static void draw_rr(ezgl::renderer* g); +static void draw_rr_edges(int from_node, ezgl::renderer* g); +static void draw_rr_pin(int inode, const ezgl::color& color, ezgl::renderer* g); +static void draw_rr_chan(int inode, const ezgl::color color, ezgl::renderer* g); +static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer* g); +static void draw_pin_to_chan_edge(int pin_node, int chan_node, ezgl::renderer* g); +static void draw_get_rr_src_sink_coords(const t_rr_node& node, float* xcen, float* ycen); +static void draw_x(float x, float y, float size, ezgl::renderer* g); +static void draw_pin_to_pin(int opin, int ipin, ezgl::renderer* g); +static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer* g); +static void draw_source_to_pin(int source_node, int opin_node, ezgl::renderer* g); +static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, bool buffered, bool switch_configurable, ezgl::renderer* g); +static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, short switch_type, ezgl::renderer* g); +static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, short switch_type, ezgl::renderer* g); +static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, int chany_node, int chany_track, enum e_edge_dir edge_dir, short switch_type, ezgl::renderer* g); +static int get_track_num(int inode, const vtr::OffsetMatrix& chanx_track, const vtr::OffsetMatrix& chany_track); static bool draw_if_net_highlighted(ClusterNetId inet); static int draw_check_rr_node_hit(float click_x, float click_y); static void draw_expand_non_configurable_rr_nodes_recurr(int from_node, - std::set &expanded_nodes); + std::set& expanded_nodes); static bool highlight_rr_nodes(float x, float y); static void highlight_blocks(double x, double y); static void draw_reset_blk_colors(); static void draw_reset_blk_color(ClusterBlockId blk_id); -static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, - float height, int size, ezgl::renderer *g); -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, - float height, ezgl::renderer *g); -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, - float height, float width, float height_scale, ezgl::renderer *g); +static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, float height, int size, ezgl::renderer* g); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, ezgl::renderer* g); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, float width, float height_scale, ezgl::renderer* g); -static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, - float incr_delay, ezgl::renderer *g); +static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, float incr_delay, ezgl::renderer* g); static void draw_routed_timing_edge(tatum::NodeId start_tnode, - tatum::NodeId end_tnode, float incr_delay, ezgl::color color, - ezgl::renderer *g); + tatum::NodeId end_tnode, + float incr_delay, + ezgl::color color, + ezgl::renderer* g); static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, - tatum::NodeId sink_tnode, ezgl::color color, ezgl::renderer *g); + tatum::NodeId sink_tnode, + ezgl::color color, + ezgl::renderer* g); static std::vector trace_routed_connection_rr_nodes( - const ClusterNetId net_id, const int driver_pin, const int sink_pin); -static bool trace_routed_connection_rr_nodes_recurr(const t_rt_node *rt_node, - int sink_rr_node, std::vector &rr_nodes_on_path); + const ClusterNetId net_id, + const int driver_pin, + const int sink_pin); +static bool trace_routed_connection_rr_nodes_recurr(const t_rt_node* rt_node, + int sink_rr_node, + std::vector& rr_nodes_on_path); static t_edge_size find_edge(int prev_inode, int inode); -static void draw_color_map_legend(const vtr::ColorMap &cmap, ezgl::renderer *g); +static void draw_color_map_legend(const vtr::ColorMap& cmap, ezgl::renderer* g); ezgl::color lighten_color(ezgl::color color, float amount); static void draw_block_pin_util(); static float get_router_expansion_cost(const t_rr_node_route_inf node_inf, - e_draw_router_expansion_cost draw_router_expansion_cost); -static void draw_router_expansion_costs(ezgl::renderer *g); - -static void draw_rr_costs(ezgl::renderer *g, const std::vector &rr_costs, - bool lowest_cost_first = true); -static void draw_main_canvas(ezgl::renderer *g); -static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application *app, - bool is_new_window); + e_draw_router_expansion_cost draw_router_expansion_cost); +static void draw_router_expansion_costs(ezgl::renderer* g); + +static void draw_rr_costs(ezgl::renderer* g, const std::vector& rr_costs, bool lowest_cost_first = true); +static void draw_main_canvas(ezgl::renderer* g); +static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application* app, + bool is_new_window); static void initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path( - ezgl::application *app, bool is_new_window); -static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application *app, - bool is_new_window); -static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application *app, - bool is_new_window); -static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application *app, - bool is_new_window); + ezgl::application* app, + bool is_new_window); +static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application* app, + bool is_new_window); +static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application* app, + bool is_new_window); +static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application* app, + bool is_new_window); static void initial_setup_NO_PICTURE_to_ROUTING_with_crit_path( - ezgl::application *app, bool is_new_window); + ezgl::application* app, + bool is_new_window); static void toggle_window_mode(GtkWidget* /*widget*/, - ezgl::application* /*app*/); -static void setup_default_ezgl_callbacks(ezgl::application *app); -static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/); -static void set_block_outline(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/); -static void set_block_text(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/); -static void clip_routing_util(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/); + ezgl::application* /*app*/); +static void setup_default_ezgl_callbacks(ezgl::application* app); +static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); +static void set_block_outline(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); +static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); +static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); static void run_graphics_commands(std::string commands); - /************************** File Scope Variables ****************************/ //The arrow head position for turning/straight-thru connections in a switch box @@ -207,41 +194,37 @@ constexpr float SB_EDGE_TURN_ARROW_POSITION = 0.2; constexpr float SB_EDGE_STRAIGHT_ARROW_POSITION = 0.95; constexpr float EMPTY_BLOCK_LIGHTEN_FACTOR = 0.20; - //Kelly's maximum contrast colors are selected to be easily distinguishable as described in: // Kenneth Kelly, "Twenty-Two Colors of Maximum Contrast", Color Eng. 3(6), 1943 //We use these to highlight a relatively small number of things (e.g. stages in a critical path, //a subset of selected net) where it is important for them to be visually distinct. const std::vector kelly_max_contrast_colors = { -//ezgl::color(242, 243, 244), //white: skip white since it doesn't contrast well with VPR's light background - ezgl::color(34, 34, 34), //black - ezgl::color(243, 195, 0), //yellow - ezgl::color(135, 86, 146), //purple - ezgl::color(243, 132, 0), //orange - ezgl::color(161, 202, 241), //light blue - ezgl::color(190, 0, 50), //red - ezgl::color(194, 178, 128), //buf - ezgl::color(132, 132, 130), //gray - ezgl::color(0, 136, 86), //green - ezgl::color(230, 143, 172), //purplish pink - ezgl::color(0, 103, 165), //blue - ezgl::color(249, 147, 121), //yellowish pink - ezgl::color(96, 78, 151), //violet - ezgl::color(246, 166, 0), //orange yellow - ezgl::color(179, 68, 108), //purplish red - ezgl::color(220, 211, 0), //greenish yellow - ezgl::color(136, 45, 23), //redish brown - ezgl::color(141, 182, 0), //yellow green - ezgl::color(101, 69, 34), //yellowish brown - ezgl::color(226, 88, 34), //reddish orange - ezgl::color(43, 61, 38) //olive green - }; - -ezgl::application::settings settings("/ezgl/main.ui", "MainWindow", - "MainCanvas", - "org.verilogtorouting.vpr.PID" + std::to_string(vtr::get_pid()), - setup_default_ezgl_callbacks); + //ezgl::color(242, 243, 244), //white: skip white since it doesn't contrast well with VPR's light background + ezgl::color(34, 34, 34), //black + ezgl::color(243, 195, 0), //yellow + ezgl::color(135, 86, 146), //purple + ezgl::color(243, 132, 0), //orange + ezgl::color(161, 202, 241), //light blue + ezgl::color(190, 0, 50), //red + ezgl::color(194, 178, 128), //buf + ezgl::color(132, 132, 130), //gray + ezgl::color(0, 136, 86), //green + ezgl::color(230, 143, 172), //purplish pink + ezgl::color(0, 103, 165), //blue + ezgl::color(249, 147, 121), //yellowish pink + ezgl::color(96, 78, 151), //violet + ezgl::color(246, 166, 0), //orange yellow + ezgl::color(179, 68, 108), //purplish red + ezgl::color(220, 211, 0), //greenish yellow + ezgl::color(136, 45, 23), //redish brown + ezgl::color(141, 182, 0), //yellow green + ezgl::color(101, 69, 34), //yellowish brown + ezgl::color(226, 88, 34), //reddish orange + ezgl::color(43, 61, 38) //olive green +}; + +ezgl::application::settings settings("/ezgl/main.ui", "MainWindow", "MainCanvas", "org.verilogtorouting.vpr.PID" + std::to_string(vtr::get_pid()), setup_default_ezgl_callbacks); ezgl::application application(settings); //bool mm_window = false; @@ -255,22 +238,20 @@ std::string rr_highlight_message; /********************** Subroutine definitions ******************************/ -void init_graphics_state(bool show_graphics_val, int gr_automode_val, - enum e_route_type route_type, bool save_graphics, - std::string graphics_commands) { +void init_graphics_state(bool show_graphics_val, int gr_automode_val, enum e_route_type route_type, bool save_graphics, std::string graphics_commands) { #ifndef NO_GRAPHICS - /* Call accessor functions to retrieve global variables. */ - t_draw_state *draw_state = get_draw_state_vars(); + /* Call accessor functions to retrieve global variables. */ + t_draw_state* draw_state = get_draw_state_vars(); - /* 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. */ + /* 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. */ - draw_state->show_graphics = show_graphics_val; - draw_state->gr_automode = gr_automode_val; - draw_state->draw_route_type = route_type; - draw_state->save_graphics = save_graphics; - draw_state->graphics_commands = graphics_commands; + draw_state->show_graphics = show_graphics_val; + draw_state->gr_automode = gr_automode_val; + draw_state->draw_route_type = route_type; + draw_state->save_graphics = save_graphics; + draw_state->graphics_commands = graphics_commands; #else //Suppress unused parameter warnings @@ -283,316 +264,314 @@ void init_graphics_state(bool show_graphics_val, int gr_automode_val, } #ifndef NO_GRAPHICS -static void draw_main_canvas(ezgl::renderer *g) { - t_draw_state *draw_state = get_draw_state_vars(); +static void draw_main_canvas(ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); - g->set_font_size(14); + g->set_font_size(14); - 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 == PLACEMENT) { - switch (draw_state->show_nets) { - case DRAW_NETS: - drawnets(g); - break; - case DRAW_LOGICAL_CONNECTIONS: - break; - default: - break; - } - } else { /* ROUTING on screen */ + if (draw_state->pic_on_screen == PLACEMENT) { + switch (draw_state->show_nets) { + case DRAW_NETS: + drawnets(g); + break; + case DRAW_LOGICAL_CONNECTIONS: + break; + default: + break; + } + } else { /* ROUTING on screen */ - switch (draw_state->show_nets) { - case DRAW_NETS: - drawroute(ALL_NETS, g); - break; - case DRAW_LOGICAL_CONNECTIONS: - // fall through - default: - draw_rr(g); - break; - } + switch (draw_state->show_nets) { + case DRAW_NETS: + drawroute(ALL_NETS, g); + break; + case DRAW_LOGICAL_CONNECTIONS: + // fall through + default: + draw_rr(g); + break; + } - 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); - draw_crit_path(g); + draw_crit_path(g); - draw_logical_connections(g); + draw_logical_connections(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 + } - if (draw_state->auto_proceed) { - //Automatically exit the event loop, so user's don't need to manually click proceed + if (draw_state->auto_proceed) { + //Automatically exit the event loop, so user's don't need to manually click proceed - //Avoid trying to repeatedly exit (which would cause errors in GTK) - draw_state->auto_proceed = false; + //Avoid trying to repeatedly exit (which would cause errors in GTK) + draw_state->auto_proceed = false; - application.quit(); //Ensure we leave the event loop - } + application.quit(); //Ensure we leave the event loop + } } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_PLACEMENT */ -static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application *app, - bool is_new_window) { - if (!is_new_window) - return; - - //button to enter window_mode, created in main.ui - GtkButton *window = (GtkButton*) app->get_object("Window"); - gtk_button_set_label(window, "Window"); - g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); - - //button to search, created in main.ui - GtkButton *search = (GtkButton*) app->get_object("Search"); - gtk_button_set_label(search, "Search"); - g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); - - //button for save graphcis, created in main.ui - GtkButton *save = (GtkButton*) app->get_object("SaveGraphics"); - g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), - app); - - //combo box for search type, created in main.ui - GObject *search_type = (GObject*) app->get_object("SearchType"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); // index 0 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), - "Block Name"); // index 1 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); // index 2 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); // index 3 - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), - "RR Node ID"); // index 4 - gtk_combo_box_set_active((GtkComboBox*) search_type, 0); // default set to Block ID which has an index 0 - - button_for_toggle_nets(); - button_for_net_max_fanout(); - button_for_net_alpha(); - button_for_toggle_blk_internal(); - button_for_toggle_block_pin_util(); - button_for_toggle_placement_macros(); +static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application* app, + bool is_new_window) { + if (!is_new_window) + return; + + //button to enter window_mode, created in main.ui + GtkButton* window = (GtkButton*)app->get_object("Window"); + gtk_button_set_label(window, "Window"); + g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); + + //button to search, created in main.ui + GtkButton* search = (GtkButton*)app->get_object("Search"); + gtk_button_set_label(search, "Search"); + g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); + + //button for save graphcis, created in main.ui + GtkButton* save = (GtkButton*)app->get_object("SaveGraphics"); + g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), + app); + + //combo box for search type, created in main.ui + GObject* search_type = (GObject*)app->get_object("SearchType"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); // index 0 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "Block Name"); // index 1 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); // index 2 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); // index 3 + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "RR Node ID"); // index 4 + gtk_combo_box_set_active((GtkComboBox*)search_type, 0); // default set to Block ID which has an index 0 + + button_for_toggle_nets(); + button_for_net_max_fanout(); + button_for_net_alpha(); + button_for_toggle_blk_internal(); + button_for_toggle_block_pin_util(); + button_for_toggle_placement_macros(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_PLACEMENT_with_crit_path */ static void initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path( - ezgl::application *app, bool is_new_window) { - initial_setup_NO_PICTURE_to_PLACEMENT(app, is_new_window); - button_for_toggle_crit_path(); + ezgl::application* app, + bool is_new_window) { + initial_setup_NO_PICTURE_to_PLACEMENT(app, is_new_window); + button_for_toggle_crit_path(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * PLACEMENT_to_ROUTING */ -static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application *app, - bool is_new_window) { - initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path(app, is_new_window); - button_for_toggle_rr(); - button_for_toggle_congestion(); - button_for_toggle_congestion_cost(); - button_for_toggle_routing_bounding_box(); - button_for_toggle_routing_util(); - button_for_toggle_router_expansion_costs(); +static void initial_setup_PLACEMENT_to_ROUTING(ezgl::application* app, + bool is_new_window) { + initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path(app, is_new_window); + button_for_toggle_rr(); + button_for_toggle_congestion(); + button_for_toggle_congestion_cost(); + button_for_toggle_routing_bounding_box(); + button_for_toggle_routing_util(); + button_for_toggle_router_expansion_costs(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * ROUTING_to_PLACEMENT */ -static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application *app, - bool is_new_window) { - initial_setup_PLACEMENT_to_ROUTING(app, is_new_window); - std::string toggle_rr = "toggle_rr"; - std::string toggle_congestion = "toggle_congestion"; - std::string toggle_routing_congestion_cost = - "toggle_routing_congestion_cost"; - std::string toggle_routing_bounding_box = "toggle_routing_bounding_box"; - std::string toggle_routing_util = "toggle_rr"; - std::string toggle_router_expansion_costs = "toggle_router_expansion_costs"; - - delete_button(toggle_rr.c_str()); - delete_button(toggle_congestion.c_str()); - delete_button(toggle_routing_congestion_cost.c_str()); - delete_button(toggle_routing_bounding_box.c_str()); - delete_button(toggle_routing_util.c_str()); - delete_button(toggle_router_expansion_costs.c_str()); +static void initial_setup_ROUTING_to_PLACEMENT(ezgl::application* app, + bool is_new_window) { + initial_setup_PLACEMENT_to_ROUTING(app, is_new_window); + std::string toggle_rr = "toggle_rr"; + std::string toggle_congestion = "toggle_congestion"; + std::string toggle_routing_congestion_cost = "toggle_routing_congestion_cost"; + std::string toggle_routing_bounding_box = "toggle_routing_bounding_box"; + std::string toggle_routing_util = "toggle_rr"; + std::string toggle_router_expansion_costs = "toggle_router_expansion_costs"; + + delete_button(toggle_rr.c_str()); + delete_button(toggle_congestion.c_str()); + delete_button(toggle_routing_congestion_cost.c_str()); + delete_button(toggle_routing_bounding_box.c_str()); + delete_button(toggle_routing_util.c_str()); + delete_button(toggle_router_expansion_costs.c_str()); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_ROUTING */ -static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application *app, - bool is_new_window) { - if (!is_new_window) - return; - - GtkButton *window = (GtkButton*) app->get_object("Window"); - gtk_button_set_label(window, "Window"); - g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); - - GtkButton *search = (GtkButton*) app->get_object("Search"); - gtk_button_set_label(search, "Search"); - g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); - - GtkButton *save = (GtkButton*) app->get_object("SaveGraphics"); - g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), - app); - - GObject *search_type = (GObject*) app->get_object("SearchType"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), - "Block Name"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), - "RR Node ID"); - - button_for_toggle_nets(); - button_for_net_max_fanout(); - button_for_net_alpha(); - button_for_toggle_blk_internal(); - button_for_toggle_block_pin_util(); - button_for_toggle_placement_macros(); - button_for_toggle_rr(); - button_for_toggle_congestion(); - button_for_toggle_congestion_cost(); - button_for_toggle_routing_bounding_box(); - button_for_toggle_routing_util(); - button_for_toggle_router_expansion_costs(); +static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application* app, + bool is_new_window) { + if (!is_new_window) + return; + + GtkButton* window = (GtkButton*)app->get_object("Window"); + gtk_button_set_label(window, "Window"); + g_signal_connect(window, "clicked", G_CALLBACK(toggle_window_mode), app); + + GtkButton* search = (GtkButton*)app->get_object("Search"); + gtk_button_set_label(search, "Search"); + g_signal_connect(search, "clicked", G_CALLBACK(search_and_highlight), app); + + GtkButton* save = (GtkButton*)app->get_object("SaveGraphics"); + g_signal_connect(save, "clicked", G_CALLBACK(save_graphics_dialog_box), + app); + + GObject* search_type = (GObject*)app->get_object("SearchType"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Block ID"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "Block Name"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net ID"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), "Net Name"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(search_type), + "RR Node ID"); + + button_for_toggle_nets(); + button_for_net_max_fanout(); + button_for_net_alpha(); + button_for_toggle_blk_internal(); + button_for_toggle_block_pin_util(); + button_for_toggle_placement_macros(); + button_for_toggle_rr(); + button_for_toggle_congestion(); + button_for_toggle_congestion_cost(); + button_for_toggle_routing_bounding_box(); + button_for_toggle_routing_util(); + button_for_toggle_router_expansion_costs(); } /* function below intializes the interface window with a set of buttons and links * signals to corresponding functions for situation where the window is opened from * NO_PICTURE_to_ROUTING_with_crit_path */ static void initial_setup_NO_PICTURE_to_ROUTING_with_crit_path( - ezgl::application *app, bool is_new_window) { - initial_setup_NO_PICTURE_to_ROUTING(app, is_new_window); - button_for_toggle_crit_path(); + ezgl::application* app, + bool is_new_window) { + initial_setup_NO_PICTURE_to_ROUTING(app, is_new_window); + button_for_toggle_crit_path(); } #endif //NO_GRAPHICS -void update_screen(ScreenUpdatePriority priority, const char *msg, - enum pic_type pic_on_screen_val, - std::shared_ptr setup_timing_info) { +void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type pic_on_screen_val, std::shared_ptr setup_timing_info) { #ifndef NO_GRAPHICS - /* Updates the screen if the user has requested graphics. The priority * - * 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(); - - if (!draw_state->show_graphics) - ezgl::set_disable_event_loop(true); - else - ezgl::set_disable_event_loop(false); - - ezgl::setup_callback_fn init_setup = nullptr; - - /* If it's the type of picture displayed has changed, set up the proper * - * buttons. */ - if (draw_state->pic_on_screen != pic_on_screen_val) { //State changed - - 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); - } - - draw_state->setup_timing_info = setup_timing_info; - - if (pic_on_screen_val == PLACEMENT - && draw_state->pic_on_screen == NO_PICTURE) { - if (setup_timing_info) { - init_setup = - initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path; - } else { - init_setup = initial_setup_NO_PICTURE_to_PLACEMENT; - } - draw_state->save_graphics_file_base = "vpr_placement"; - - } else if (pic_on_screen_val == ROUTING - && draw_state->pic_on_screen == PLACEMENT) { - //Routing, opening after placement - init_setup = initial_setup_PLACEMENT_to_ROUTING; - draw_state->save_graphics_file_base = "vpr_routing"; - - } else if (pic_on_screen_val == PLACEMENT - && draw_state->pic_on_screen == ROUTING) { - init_setup = initial_setup_ROUTING_to_PLACEMENT; - draw_state->save_graphics_file_base = "vpr_placement"; - - } else if (pic_on_screen_val == ROUTING - && draw_state->pic_on_screen == NO_PICTURE) { - //Routing opening first - if (setup_timing_info) { - init_setup = initial_setup_NO_PICTURE_to_ROUTING_with_crit_path; - } else { - init_setup = initial_setup_NO_PICTURE_to_ROUTING; - } - draw_state->save_graphics_file_base = "vpr_routing"; - } - - draw_state->pic_on_screen = pic_on_screen_val; - - } else { - //No change (e.g. paused) - init_setup = nullptr; - } - - bool state_change = (init_setup != nullptr); - 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. - //However, by default this causes graphics to pause for user interaction. - // - //If the priority is such that we shouldn't pause we need to continue automatically, so - //the user won't need to click manually. - draw_state->auto_proceed = (state_change && !should_pause); - - if (state_change //Must update buttons - || should_pause //The priority means graphics should pause for user interaction - || draw_state->forced_pause) { //The user asked to pause - - if (draw_state->forced_pause) { - VTR_LOG("Pausing in interactive graphics (user pressed 'Pause')\n"); - draw_state->forced_pause = false; //Reset pause flag - } - - application.run(init_setup, act_on_mouse_press, act_on_mouse_move, - act_on_key_press); - - if (!draw_state->graphics_commands.empty()) { - run_graphics_commands(draw_state->graphics_commands); - } - } - - if (draw_state->show_graphics) { - application.update_message(msg); - application.refresh_drawing(); - application.flush_drawing(); - } - - if (draw_state->save_graphics) { - std::string extension = "pdf"; - save_graphics(extension, draw_state->save_graphics_file_base); - } + /* Updates the screen if the user has requested graphics. The priority * + * 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(); + + if (!draw_state->show_graphics) + ezgl::set_disable_event_loop(true); + else + ezgl::set_disable_event_loop(false); + + ezgl::setup_callback_fn init_setup = nullptr; + + /* If it's the type of picture displayed has changed, set up the proper * + * buttons. */ + if (draw_state->pic_on_screen != pic_on_screen_val) { //State changed + + 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); + } + + draw_state->setup_timing_info = setup_timing_info; + + if (pic_on_screen_val == PLACEMENT + && draw_state->pic_on_screen == NO_PICTURE) { + if (setup_timing_info) { + init_setup = initial_setup_NO_PICTURE_to_PLACEMENT_with_crit_path; + } else { + init_setup = initial_setup_NO_PICTURE_to_PLACEMENT; + } + draw_state->save_graphics_file_base = "vpr_placement"; + + } else if (pic_on_screen_val == ROUTING + && draw_state->pic_on_screen == PLACEMENT) { + //Routing, opening after placement + init_setup = initial_setup_PLACEMENT_to_ROUTING; + draw_state->save_graphics_file_base = "vpr_routing"; + + } else if (pic_on_screen_val == PLACEMENT + && draw_state->pic_on_screen == ROUTING) { + init_setup = initial_setup_ROUTING_to_PLACEMENT; + draw_state->save_graphics_file_base = "vpr_placement"; + + } else if (pic_on_screen_val == ROUTING + && draw_state->pic_on_screen == NO_PICTURE) { + //Routing opening first + if (setup_timing_info) { + init_setup = initial_setup_NO_PICTURE_to_ROUTING_with_crit_path; + } else { + init_setup = initial_setup_NO_PICTURE_to_ROUTING; + } + draw_state->save_graphics_file_base = "vpr_routing"; + } + + draw_state->pic_on_screen = pic_on_screen_val; + + } else { + //No change (e.g. paused) + init_setup = nullptr; + } + + bool state_change = (init_setup != nullptr); + 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. + //However, by default this causes graphics to pause for user interaction. + // + //If the priority is such that we shouldn't pause we need to continue automatically, so + //the user won't need to click manually. + draw_state->auto_proceed = (state_change && !should_pause); + + if (state_change //Must update buttons + || should_pause //The priority means graphics should pause for user interaction + || draw_state->forced_pause) { //The user asked to pause + + if (draw_state->forced_pause) { + VTR_LOG("Pausing in interactive graphics (user pressed 'Pause')\n"); + draw_state->forced_pause = false; //Reset pause flag + } + + application.run(init_setup, act_on_mouse_press, act_on_mouse_move, + act_on_key_press); + + if (!draw_state->graphics_commands.empty()) { + run_graphics_commands(draw_state->graphics_commands); + } + } + + if (draw_state->show_graphics) { + application.update_message(msg); + application.refresh_drawing(); + application.flush_drawing(); + } + + if (draw_state->save_graphics) { + std::string extension = "pdf"; + save_graphics(extension, draw_state->save_graphics_file_base); + } #else (void)setup_timing_info; @@ -604,368 +583,358 @@ void update_screen(ScreenUpdatePriority priority, const char *msg, #ifndef NO_GRAPHICS static void toggle_window_mode(GtkWidget* /*widget*/, - ezgl::application* /*app*/) { - window_mode = true; + ezgl::application* /*app*/) { + window_mode = true; } -void toggle_nets(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_nets button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - - // get the pointer to the toggle_nets button - std::string button_name = "toggle_nets"; - auto toggle_nets = find_button(button_name.c_str()); - - // use the pointer to get the active text - enum e_draw_nets new_state; - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_nets)); - - // assign corresponding enum value to draw_state->show_nets - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_NETS; - else if (strcmp(combo_box_content, "Nets") == 0) { - new_state = DRAW_NETS; - } else { // "Logical Connections" - new_state = DRAW_LOGICAL_CONNECTIONS; - } - draw_state->reset_nets_congestion_and_rr(); - draw_state->show_nets = new_state; - - //free dynamically allocated pointers - g_free(combo_box_content); - - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +void toggle_nets(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_nets button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + + // get the pointer to the toggle_nets button + std::string button_name = "toggle_nets"; + auto toggle_nets = find_button(button_name.c_str()); + + // use the pointer to get the active text + enum e_draw_nets new_state; + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_nets)); + + // assign corresponding enum value to draw_state->show_nets + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_NETS; + else if (strcmp(combo_box_content, "Nets") == 0) { + new_state = DRAW_NETS; + } else { // "Logical Connections" + new_state = DRAW_LOGICAL_CONNECTIONS; + } + draw_state->reset_nets_congestion_and_rr(); + draw_state->show_nets = new_state; + + //free dynamically allocated pointers + g_free(combo_box_content); + + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } void toggle_rr(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { - /* this is the callback function for runtime created toggle_rr button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_rr"; - auto toggle_rr = find_button(button_name.c_str()); - - enum e_draw_rr_toggle new_state; - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_rr)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_RR; - else if (strcmp(combo_box_content, "Nodes") == 0) - new_state = DRAW_NODES_RR; - else if (strcmp(combo_box_content, "Nodes SBox") == 0) - new_state = DRAW_NODES_SBOX_RR; - else if (strcmp(combo_box_content, "Nodes SBox CBox") == 0) - new_state = DRAW_NODES_SBOX_CBOX_RR; - else if (strcmp(combo_box_content, "Nodes SBox CBox Internal") == 0) - new_state = DRAW_NODES_SBOX_CBOX_INTERNAL_RR; - else - // all rr - new_state = DRAW_ALL_RR; - - //free dynamically allocated pointers - g_free(combo_box_content); - - draw_state->reset_nets_congestion_and_rr(); - draw_state->draw_rr_toggle = new_state; - - application.update_message(draw_state->default_message); - application.refresh_drawing(); + /* this is the callback function for runtime created toggle_rr button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_rr"; + auto toggle_rr = find_button(button_name.c_str()); + + enum e_draw_rr_toggle new_state; + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_rr)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_RR; + else if (strcmp(combo_box_content, "Nodes") == 0) + new_state = DRAW_NODES_RR; + else if (strcmp(combo_box_content, "Nodes SBox") == 0) + new_state = DRAW_NODES_SBOX_RR; + else if (strcmp(combo_box_content, "Nodes SBox CBox") == 0) + new_state = DRAW_NODES_SBOX_CBOX_RR; + else if (strcmp(combo_box_content, "Nodes SBox CBox Internal") == 0) + new_state = DRAW_NODES_SBOX_CBOX_INTERNAL_RR; + else + // all rr + new_state = DRAW_ALL_RR; + + //free dynamically allocated pointers + g_free(combo_box_content); + + draw_state->reset_nets_congestion_and_rr(); + draw_state->draw_rr_toggle = new_state; + + application.update_message(draw_state->default_message); + application.refresh_drawing(); } -void toggle_congestion(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_congestion button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_congestion"; - auto toggle_congestion = find_button(button_name.c_str()); - - enum e_draw_congestion new_state; - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_congestion)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_CONGEST; - else if (strcmp(combo_box_content, "Congested") == 0) - new_state = DRAW_CONGESTED; - else - // congested with nets - new_state = DRAW_CONGESTED_WITH_NETS; - - draw_state->reset_nets_congestion_and_rr(); - draw_state->show_congestion = new_state; - if (draw_state->show_congestion == DRAW_NO_CONGEST) { - application.update_message(draw_state->default_message); - } - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_congestion(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_congestion button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_congestion"; + auto toggle_congestion = find_button(button_name.c_str()); + + enum e_draw_congestion new_state; + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_congestion)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_CONGEST; + else if (strcmp(combo_box_content, "Congested") == 0) + new_state = DRAW_CONGESTED; + else + // congested with nets + new_state = DRAW_CONGESTED_WITH_NETS; + + draw_state->reset_nets_congestion_and_rr(); + draw_state->show_congestion = new_state; + if (draw_state->show_congestion == DRAW_NO_CONGEST) { + application.update_message(draw_state->default_message); + } + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_routing_congestion_cost(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_routing_congestion_cost button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_routing_congestion_cost"; - auto toggle_routing_congestion_cost = find_button(button_name.c_str()); - enum e_draw_routing_costs new_state; - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_routing_congestion_cost)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Total Routing Costs") == 0) - new_state = DRAW_TOTAL_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Log Total Routing Costs") == 0) - new_state = DRAW_LOG_TOTAL_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Acc Routing Costs") == 0) - new_state = DRAW_ACC_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Log Acc Routing Costs") == 0) - new_state = DRAW_LOG_ACC_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Pres Routing Costs") == 0) - new_state = DRAW_PRES_ROUTING_COSTS; - else if (strcmp(combo_box_content, "Log Pres Routing Costs") == 0) - new_state = DRAW_LOG_PRES_ROUTING_COSTS; - else - new_state = DRAW_BASE_ROUTING_COSTS; - - draw_state->reset_nets_congestion_and_rr(); - draw_state->show_routing_costs = new_state; - g_free(combo_box_content); - if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_routing_congestion_cost(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_routing_congestion_cost button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_routing_congestion_cost"; + auto toggle_routing_congestion_cost = find_button(button_name.c_str()); + enum e_draw_routing_costs new_state; + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_routing_congestion_cost)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Total Routing Costs") == 0) + new_state = DRAW_TOTAL_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Log Total Routing Costs") == 0) + new_state = DRAW_LOG_TOTAL_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Acc Routing Costs") == 0) + new_state = DRAW_ACC_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Log Acc Routing Costs") == 0) + new_state = DRAW_LOG_ACC_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Pres Routing Costs") == 0) + new_state = DRAW_PRES_ROUTING_COSTS; + else if (strcmp(combo_box_content, "Log Pres Routing Costs") == 0) + new_state = DRAW_LOG_PRES_ROUTING_COSTS; + else + new_state = DRAW_BASE_ROUTING_COSTS; + + draw_state->reset_nets_congestion_and_rr(); + draw_state->show_routing_costs = new_state; + g_free(combo_box_content); + if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } -void toggle_routing_bounding_box(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_routing_bounding_box button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - auto &route_ctx = g_vpr_ctx.routing(); - // get the pointer to the toggle_routing_bounding_box button - std::string button_name = "toggle_routing_bounding_box"; - auto toggle_routing_bounding_box = find_button(button_name.c_str()); - - if (route_ctx.route_bb.size() == 0) - return; //Nothing to draw - - // use the pointer to get the active value - int new_value = gtk_spin_button_get_value_as_int( - (GtkSpinButton*) toggle_routing_bounding_box); - - // assign value to draw_state->show_routing_bb, bound check + set OPEN when it's -1 (draw nothing) - if (new_value < -1) - draw_state->show_routing_bb = -1; - else if (new_value == -1) - draw_state->show_routing_bb = OPEN; - else if (new_value >= (int) (route_ctx.route_bb.size())) - draw_state->show_routing_bb = route_ctx.route_bb.size() - 1; - else - draw_state->show_routing_bb = new_value; - - //redraw - if ((int) (draw_state->show_routing_bb) - == (int) ((int) (route_ctx.route_bb.size()) - 1)) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_routing_bounding_box(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_routing_bounding_box button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + auto& route_ctx = g_vpr_ctx.routing(); + // get the pointer to the toggle_routing_bounding_box button + std::string button_name = "toggle_routing_bounding_box"; + auto toggle_routing_bounding_box = find_button(button_name.c_str()); + + if (route_ctx.route_bb.size() == 0) + return; //Nothing to draw + + // use the pointer to get the active value + int new_value = gtk_spin_button_get_value_as_int( + (GtkSpinButton*)toggle_routing_bounding_box); + + // assign value to draw_state->show_routing_bb, bound check + set OPEN when it's -1 (draw nothing) + if (new_value < -1) + draw_state->show_routing_bb = -1; + else if (new_value == -1) + draw_state->show_routing_bb = OPEN; + else if (new_value >= (int)(route_ctx.route_bb.size())) + draw_state->show_routing_bb = route_ctx.route_bb.size() - 1; + else + draw_state->show_routing_bb = new_value; + + //redraw + if ((int)(draw_state->show_routing_bb) + == (int)((int)(route_ctx.route_bb.size()) - 1)) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } -void toggle_routing_util(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_routing_util button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_routing_util"; - auto toggle_routing_util = find_button(button_name.c_str()); - - enum e_draw_routing_util new_state; - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_routing_util)); - if (strcmp(combo_box_content, "None") == 0) - new_state = DRAW_NO_ROUTING_UTIL; - else if (strcmp(combo_box_content, "Routing Util") == 0) - new_state = DRAW_ROUTING_UTIL; - else if (strcmp(combo_box_content, "Routing Util with Value") == 0) - new_state = DRAW_ROUTING_UTIL_WITH_VALUE; - else if (strcmp(combo_box_content, "Routing Util with Formula") == 0) - new_state = DRAW_ROUTING_UTIL_WITH_FORMULA; - else - new_state = DRAW_ROUTING_UTIL_OVER_BLOCKS; - - g_free(combo_box_content); - draw_state->show_routing_util = new_state; - - if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_routing_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_routing_util button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_routing_util"; + auto toggle_routing_util = find_button(button_name.c_str()); + + enum e_draw_routing_util new_state; + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_routing_util)); + if (strcmp(combo_box_content, "None") == 0) + new_state = DRAW_NO_ROUTING_UTIL; + else if (strcmp(combo_box_content, "Routing Util") == 0) + new_state = DRAW_ROUTING_UTIL; + else if (strcmp(combo_box_content, "Routing Util with Value") == 0) + new_state = DRAW_ROUTING_UTIL_WITH_VALUE; + else if (strcmp(combo_box_content, "Routing Util with Formula") == 0) + new_state = DRAW_ROUTING_UTIL_WITH_FORMULA; + else + new_state = DRAW_ROUTING_UTIL_OVER_BLOCKS; + + g_free(combo_box_content); + draw_state->show_routing_util = new_state; + + if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } -void toggle_blk_internal(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_blk_internal button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_blk_internal"; - auto toggle_blk_internal = find_button(button_name.c_str()); - - int new_value = gtk_spin_button_get_value_as_int( - (GtkSpinButton*) toggle_blk_internal); - 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; - else - draw_state->show_blk_internal = new_value; - application.refresh_drawing(); +void toggle_blk_internal(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_blk_internal button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_blk_internal"; + auto toggle_blk_internal = find_button(button_name.c_str()); + + int new_value = gtk_spin_button_get_value_as_int( + (GtkSpinButton*)toggle_blk_internal); + 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; + else + draw_state->show_blk_internal = new_value; + application.refresh_drawing(); } -void toggle_block_pin_util(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_block_pin_util button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_block_pin_util"; - auto toggle_block_pin_util = find_button(button_name.c_str()); - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_block_pin_util)); - if (strcmp(combo_box_content, "None") == 0) { - draw_state->show_blk_pin_util = DRAW_NO_BLOCK_PIN_UTIL; - draw_reset_blk_colors(); - application.update_message(draw_state->default_message); - } else if (strcmp(combo_box_content, "All") == 0) - draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_TOTAL; - else if (strcmp(combo_box_content, "Inputs") == 0) - draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_INPUTS; - else - draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_OUTPUTS; - - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_block_pin_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_block_pin_util button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_block_pin_util"; + auto toggle_block_pin_util = find_button(button_name.c_str()); + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_block_pin_util)); + if (strcmp(combo_box_content, "None") == 0) { + draw_state->show_blk_pin_util = DRAW_NO_BLOCK_PIN_UTIL; + draw_reset_blk_colors(); + application.update_message(draw_state->default_message); + } else if (strcmp(combo_box_content, "All") == 0) + draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_TOTAL; + else if (strcmp(combo_box_content, "Inputs") == 0) + draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_INPUTS; + else + draw_state->show_blk_pin_util = DRAW_BLOCK_PIN_UTIL_OUTPUTS; + + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_placement_macros(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_placement_macros button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_placement_macros"; - auto toggle_placement_macros = find_button(button_name.c_str()); - - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_placement_macros)); - if (strcmp(combo_box_content, "None") == 0) - draw_state->show_placement_macros = DRAW_NO_PLACEMENT_MACROS; - else - draw_state->show_placement_macros = DRAW_PLACEMENT_MACROS; - - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_placement_macros(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_placement_macros button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_placement_macros"; + auto toggle_placement_macros = find_button(button_name.c_str()); + + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_placement_macros)); + if (strcmp(combo_box_content, "None") == 0) + draw_state->show_placement_macros = DRAW_NO_PLACEMENT_MACROS; + else + draw_state->show_placement_macros = DRAW_PLACEMENT_MACROS; + + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_crit_path(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_crit_path button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_crit_path"; - auto toggle_crit_path = find_button(button_name.c_str()); - - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_crit_path)); - if (strcmp(combo_box_content, "None") == 0) { - draw_state->show_crit_path = DRAW_NO_CRIT_PATH; - } else if (strcmp(combo_box_content, "Crit Path Flylines") == 0) - draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES; - else if (strcmp(combo_box_content, "Crit Path Flylines Delays") == 0) - draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES_DELAYS; - else if (strcmp(combo_box_content, "Crit Path Routing") == 0) - draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING; - else - // Crit Path Routing Delays - draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING_DELAYS; - - g_free(combo_box_content); - application.refresh_drawing(); +void toggle_crit_path(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_crit_path button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_crit_path"; + auto toggle_crit_path = find_button(button_name.c_str()); + + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_crit_path)); + if (strcmp(combo_box_content, "None") == 0) { + draw_state->show_crit_path = DRAW_NO_CRIT_PATH; + } else if (strcmp(combo_box_content, "Crit Path Flylines") == 0) + draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES; + else if (strcmp(combo_box_content, "Crit Path Flylines Delays") == 0) + draw_state->show_crit_path = DRAW_CRIT_PATH_FLYLINES_DELAYS; + else if (strcmp(combo_box_content, "Crit Path Routing") == 0) + draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING; + else + // Crit Path Routing Delays + draw_state->show_crit_path = DRAW_CRIT_PATH_ROUTING_DELAYS; + + g_free(combo_box_content); + application.refresh_drawing(); } -void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created toggle_router_expansion_costs button - * which is written in button.cpp */ - t_draw_state *draw_state = get_draw_state_vars(); - std::string button_name = "toggle_router_expansion_costs"; - auto toggle_router_expansion_costs = find_button(button_name.c_str()); - - e_draw_router_expansion_cost new_state; - gchar *combo_box_content = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(toggle_router_expansion_costs)); - if (strcmp(combo_box_content, "None") == 0) { - new_state = DRAW_NO_ROUTER_EXPANSION_COST; - } else if (strcmp(combo_box_content, "Total") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL; - } else if (strcmp(combo_box_content, "Known") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN; - } else if (strcmp(combo_box_content, "Expected") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED; - } else if (strcmp(combo_box_content, "Total (with edges)") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES; - } else if (strcmp(combo_box_content, "Known (with edges)") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES; - } else if (strcmp(combo_box_content, "Expected (with edges)") == 0) { - new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES; - } else { - VPR_THROW(VPR_ERROR_DRAW, "Unrecognzied draw RR cost option"); - } - - g_free(combo_box_content); - draw_state->show_router_expansion_cost = new_state; - - if (draw_state->show_router_expansion_cost - == DRAW_NO_ROUTER_EXPANSION_COST) { - application.update_message(draw_state->default_message); - } - application.refresh_drawing(); +void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_router_expansion_costs button + * which is written in button.cpp */ + t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_router_expansion_costs"; + auto toggle_router_expansion_costs = find_button(button_name.c_str()); + + e_draw_router_expansion_cost new_state; + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_router_expansion_costs)); + if (strcmp(combo_box_content, "None") == 0) { + new_state = DRAW_NO_ROUTER_EXPANSION_COST; + } else if (strcmp(combo_box_content, "Total") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL; + } else if (strcmp(combo_box_content, "Known") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN; + } else if (strcmp(combo_box_content, "Expected") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED; + } else if (strcmp(combo_box_content, "Total (with edges)") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES; + } else if (strcmp(combo_box_content, "Known (with edges)") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES; + } else if (strcmp(combo_box_content, "Expected (with edges)") == 0) { + new_state = DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES; + } else { + VPR_THROW(VPR_ERROR_DRAW, "Unrecognzied draw RR cost option"); + } + + g_free(combo_box_content); + draw_state->show_router_expansion_cost = new_state; + + if (draw_state->show_router_expansion_cost + == DRAW_NO_ROUTER_EXPANSION_COST) { + application.update_message(draw_state->default_message); + } + application.refresh_drawing(); } #endif // NO_GRAPHICS -void alloc_draw_structs(const t_arch *arch) { +void alloc_draw_structs(const t_arch* arch) { #ifndef NO_GRAPHICS - /* Call accessor functions to retrieve global variables. */ - t_draw_coords *draw_coords = get_draw_coords_vars(); - t_draw_state *draw_state = get_draw_state_vars(); - auto &device_ctx = g_vpr_ctx.device(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - - /* Allocate the structures needed to draw the placement and routing-> Set * - * up the default colors for blocks and nets. */ - draw_coords->tile_x = (float*) vtr::malloc( - device_ctx.grid.width() * sizeof(float)); - draw_coords->tile_y = (float*) vtr::malloc( - device_ctx.grid.height() * sizeof(float)); - - /* For sub-block drawings inside clbs */ - draw_internal_alloc_blk(); - - draw_state->net_color.resize(cluster_ctx.clb_nlist.nets().size()); - draw_state->block_color_.resize(cluster_ctx.clb_nlist.blocks().size()); - draw_state->use_default_block_color_.resize( - cluster_ctx.clb_nlist.blocks().size()); - - /* Space is allocated for draw_rr_node but not initialized because we do * - * not yet know information about the routing resources. */ - draw_state->draw_rr_node = (t_draw_rr_node*) vtr::malloc( - device_ctx.rr_nodes.size() * sizeof(t_draw_rr_node)); - - draw_state->arch_info = arch; - - deselect_all(); /* Set initial colors */ + /* Call accessor functions to retrieve global variables. */ + t_draw_coords* draw_coords = get_draw_coords_vars(); + t_draw_state* draw_state = get_draw_state_vars(); + auto& device_ctx = g_vpr_ctx.device(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + + /* Allocate the structures needed to draw the placement and routing-> Set * + * up the default colors for blocks and nets. */ + draw_coords->tile_x = (float*)vtr::malloc( + device_ctx.grid.width() * sizeof(float)); + draw_coords->tile_y = (float*)vtr::malloc( + device_ctx.grid.height() * sizeof(float)); + + /* For sub-block drawings inside clbs */ + draw_internal_alloc_blk(); + + draw_state->net_color.resize(cluster_ctx.clb_nlist.nets().size()); + draw_state->block_color_.resize(cluster_ctx.clb_nlist.blocks().size()); + draw_state->use_default_block_color_.resize( + cluster_ctx.clb_nlist.blocks().size()); + + /* Space is allocated for draw_rr_node but not initialized because we do * + * not yet know information about the routing resources. */ + draw_state->draw_rr_node = (t_draw_rr_node*)vtr::malloc( + device_ctx.rr_nodes.size() * sizeof(t_draw_rr_node)); + + draw_state->arch_info = arch; + + deselect_all(); /* Set initial colors */ #else (void)arch; #endif // NO_GRAPHICS @@ -973,25 +942,25 @@ void alloc_draw_structs(const t_arch *arch) { void free_draw_structs() { #ifndef NO_GRAPHICS - /* Free everything allocated by alloc_draw_structs. Called after close_graphics() * - * in vpr_api.c. - * - * For safety, set all the array pointers to NULL in case any data - * structure gets freed twice. */ - t_draw_state *draw_state = get_draw_state_vars(); - t_draw_coords *draw_coords = get_draw_coords_vars(); - - if (draw_coords != nullptr) { - free(draw_coords->tile_x); - draw_coords->tile_x = nullptr; - free(draw_coords->tile_y); - draw_coords->tile_y = nullptr; - } - - if (draw_state != nullptr) { - free(draw_state->draw_rr_node); - draw_state->draw_rr_node = nullptr; - } + /* Free everything allocated by alloc_draw_structs. Called after close_graphics() * + * in vpr_api.c. + * + * For safety, set all the array pointers to NULL in case any data + * structure gets freed twice. */ + t_draw_state* draw_state = get_draw_state_vars(); + t_draw_coords* draw_coords = get_draw_coords_vars(); + + if (draw_coords != nullptr) { + free(draw_coords->tile_x); + draw_coords->tile_x = nullptr; + free(draw_coords->tile_y); + draw_coords->tile_y = nullptr; + } + + if (draw_state != nullptr) { + free(draw_state->draw_rr_node); + draw_state->draw_rr_node = nullptr; + } #else ; #endif /* NO_GRAPHICS */ @@ -999,68 +968,69 @@ void free_draw_structs() { void init_draw_coords(float width_val) { #ifndef NO_GRAPHICS - /* Load the arrays containing the left and bottom coordinates of the clbs * - * forming the FPGA. tile_width_val sets the width and height of a drawn * - * clb. */ - 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(); - - if (!draw_state->show_graphics && !draw_state->save_graphics - && draw_state->graphics_commands.empty()) - return; //do not initialize only if --disp off and --save_graphics off - /* Each time routing is on screen, need to reallocate the color of each * - * rr_node, as the number of rr_nodes may change. */ - if (device_ctx.rr_nodes.size() != 0) { - draw_state->draw_rr_node = (t_draw_rr_node*) vtr::realloc( - draw_state->draw_rr_node, - (device_ctx.rr_nodes.size()) * sizeof(t_draw_rr_node)); - for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { - draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[i].node_highlighted = false; - } - } - draw_coords->tile_width = width_val; - draw_coords->pin_size = 0.3; - for (const auto &type : device_ctx.physical_tile_types) { - auto num_pins = type.num_pins; - if (num_pins > 0) { - draw_coords->pin_size = std::min(draw_coords->pin_size, - (draw_coords->get_tile_width() / (4.0F * num_pins))); - } - } - - size_t j = 0; - for (size_t i = 0; i < (device_ctx.grid.width() - 1); i++) { - draw_coords->tile_x[i] = (i * draw_coords->get_tile_width()) + j; - j += device_ctx.chan_width.y_list[i] + 1; /* N wires need N+1 units of space */ - } - draw_coords->tile_x[device_ctx.grid.width() - 1] = ((device_ctx.grid.width() - - 1) * draw_coords->get_tile_width()) + j; - j = 0; - for (size_t i = 0; i < (device_ctx.grid.height() - 1); ++i) { - draw_coords->tile_y[i] = (i * draw_coords->get_tile_width()) + j; - j += device_ctx.chan_width.x_list[i] + 1; - } - draw_coords->tile_y[device_ctx.grid.height() - 1] = - ((device_ctx.grid.height() - 1) * draw_coords->get_tile_width()) - + j; - /* Load coordinates of sub-blocks inside the clbs */ - draw_internal_init_blk(); - //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 - constexpr float VISIBLE_MARGIN = 0.01; - - float draw_width = draw_coords->tile_x[device_ctx.grid.width() - 1] - + draw_coords->get_tile_width(); - float draw_height = draw_coords->tile_y[device_ctx.grid.height() - 1] - + draw_coords->get_tile_width(); - - initial_world = ezgl::rectangle( - { -VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height }, - { (1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN) - * draw_height }); + /* Load the arrays containing the left and bottom coordinates of the clbs * + * forming the FPGA. tile_width_val sets the width and height of a drawn * + * clb. */ + 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(); + + if (!draw_state->show_graphics && !draw_state->save_graphics + && draw_state->graphics_commands.empty()) + return; //do not initialize only if --disp off and --save_graphics off + /* Each time routing is on screen, need to reallocate the color of each * + * rr_node, as the number of rr_nodes may change. */ + if (device_ctx.rr_nodes.size() != 0) { + draw_state->draw_rr_node = (t_draw_rr_node*)vtr::realloc( + draw_state->draw_rr_node, + (device_ctx.rr_nodes.size()) * sizeof(t_draw_rr_node)); + for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { + draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[i].node_highlighted = false; + } + } + draw_coords->tile_width = width_val; + draw_coords->pin_size = 0.3; + for (const auto& type : device_ctx.physical_tile_types) { + auto num_pins = type.num_pins; + if (num_pins > 0) { + draw_coords->pin_size = std::min(draw_coords->pin_size, + (draw_coords->get_tile_width() / (4.0F * num_pins))); + } + } + + size_t j = 0; + for (size_t i = 0; i < (device_ctx.grid.width() - 1); i++) { + draw_coords->tile_x[i] = (i * draw_coords->get_tile_width()) + j; + j += device_ctx.chan_width.y_list[i] + 1; /* N wires need N+1 units of space */ + } + draw_coords->tile_x[device_ctx.grid.width() - 1] = ((device_ctx.grid.width() + - 1) + * draw_coords->get_tile_width()) + + j; + j = 0; + for (size_t i = 0; i < (device_ctx.grid.height() - 1); ++i) { + draw_coords->tile_y[i] = (i * draw_coords->get_tile_width()) + j; + j += device_ctx.chan_width.x_list[i] + 1; + } + draw_coords->tile_y[device_ctx.grid.height() - 1] = ((device_ctx.grid.height() - 1) * draw_coords->get_tile_width()) + + j; + /* Load coordinates of sub-blocks inside the clbs */ + draw_internal_init_blk(); + //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 + constexpr float VISIBLE_MARGIN = 0.01; + + float draw_width = draw_coords->tile_x[device_ctx.grid.width() - 1] + + draw_coords->get_tile_width(); + float draw_height = draw_coords->tile_y[device_ctx.grid.height() - 1] + + draw_coords->get_tile_width(); + + initial_world = ezgl::rectangle( + {-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height}, + {(1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN) + * draw_height}); #else (void)width_val; #endif /* NO_GRAPHICS */ @@ -1070,153 +1040,149 @@ void init_draw_coords(float width_val) { /* Draws the blocks placed on the proper clbs. Occupied blocks are darker colours * * while empty ones are lighter colours and have a dashed border. */ -static void drawplace(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(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_ctx = g_vpr_ctx.placement(); - - ClusterBlockId bnum; - int num_sub_tiles; - - g->set_line_width(0); - for (size_t i = 0; i < device_ctx.grid.width(); i++) { - for (size_t j = 0; j < device_ctx.grid.height(); j++) { - /* Only the first block of a group should control drawing */ - if (device_ctx.grid[i][j].width_offset > 0 - || device_ctx.grid[i][j].height_offset > 0) - continue; - - num_sub_tiles = device_ctx.grid[i][j].type->capacity; - /* Don't draw if tile capacity is zero. eg-> corners. */ - if (num_sub_tiles == 0) { - continue; - } - - for (int k = 0; k < num_sub_tiles; ++k) { - /* Look at the tile at start of large block */ - bnum = place_ctx.grid_blocks[i][j].blocks[k]; - /* Fill background for the clb. Do not fill if "show_blk_internal" - * is toggled. - */ - if (bnum == INVALID_BLOCK_ID) - continue; - - //Determine the block color and logical type - ezgl::color block_color; - t_logical_block_type_ptr logical_block_type = nullptr; - - //flag whether the current location is highlighted with a special color or not - bool current_loc_is_highlighted = false; - - if (placer_breakpoint_reached()) - current_loc_is_highlighted = - highlight_loc_with_specific_color(int(i), int(j), - block_color); - - // No color specified at this location; use the block color. - if (current_loc_is_highlighted == false) { - if (bnum != EMPTY_BLOCK_ID) { - block_color = draw_state->block_color(bnum); - } else { - block_color = get_block_type_color( - device_ctx.grid[i][j].type); - block_color = lighten_color(block_color, - EMPTY_BLOCK_LIGHTEN_FACTOR); - } - } - - auto tile_type = device_ctx.grid[i][j].type; - logical_block_type = pick_logical_type(tile_type); - - g->set_color(block_color); - /* Get coords of current sub_tile */ - ezgl::rectangle abs_clb_bbox = - draw_coords->get_absolute_clb_bbox(i, j, k, - logical_block_type); - ezgl::point2d center = abs_clb_bbox.center(); - - g->fill_rectangle(abs_clb_bbox); - - g->set_color(ezgl::BLACK); - - g->set_line_dash( - (EMPTY_BLOCK_ID == bnum) ? - ezgl::line_dash::asymmetric_5_3 : - ezgl::line_dash::none); - if (draw_state->draw_block_outlines) { - g->draw_rectangle(abs_clb_bbox); - } - - if (draw_state->draw_block_text) { - /* Draw text if the space has parts of the netlist */ - if (bnum != EMPTY_BLOCK_ID && bnum != INVALID_BLOCK_ID) { - std::string name = cluster_ctx.clb_nlist.block_name( - bnum) - + vtr::string_fmt(" (#%zu)", size_t(bnum)); - - g->draw_text(center, name.c_str(), abs_clb_bbox.width(), - abs_clb_bbox.height()); - } - /* Draw text for block type so that user knows what block */ - if (device_ctx.grid[i][j].width_offset == 0 - && device_ctx.grid[i][j].height_offset == 0) { - std::string block_type_loc = - device_ctx.grid[i][j].type->name; - block_type_loc += vtr::string_fmt(" (%d,%d)", i, j); - - g->draw_text( - center - - ezgl::point2d(0, - abs_clb_bbox.height() / 4), - block_type_loc.c_str(), abs_clb_bbox.width(), - abs_clb_bbox.height()); - } - } - } - } - } -} +static void drawplace(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(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + + ClusterBlockId bnum; + int num_sub_tiles; + + g->set_line_width(0); + for (size_t i = 0; i < device_ctx.grid.width(); i++) { + for (size_t j = 0; j < device_ctx.grid.height(); j++) { + /* Only the first block of a group should control drawing */ + if (device_ctx.grid[i][j].width_offset > 0 + || device_ctx.grid[i][j].height_offset > 0) + continue; + + num_sub_tiles = device_ctx.grid[i][j].type->capacity; + /* Don't draw if tile capacity is zero. eg-> corners. */ + if (num_sub_tiles == 0) { + continue; + } + + for (int k = 0; k < num_sub_tiles; ++k) { + /* Look at the tile at start of large block */ + bnum = place_ctx.grid_blocks[i][j].blocks[k]; + /* Fill background for the clb. Do not fill if "show_blk_internal" + * is toggled. + */ + if (bnum == INVALID_BLOCK_ID) + continue; + + //Determine the block color and logical type + ezgl::color block_color; + t_logical_block_type_ptr logical_block_type = nullptr; + + //flag whether the current location is highlighted with a special color or not + bool current_loc_is_highlighted = false; + + if (placer_breakpoint_reached()) + current_loc_is_highlighted = highlight_loc_with_specific_color(int(i), int(j), + block_color); + + // No color specified at this location; use the block color. + if (current_loc_is_highlighted == false) { + if (bnum != EMPTY_BLOCK_ID) { + block_color = draw_state->block_color(bnum); + } else { + block_color = get_block_type_color( + device_ctx.grid[i][j].type); + block_color = lighten_color(block_color, + EMPTY_BLOCK_LIGHTEN_FACTOR); + } + } + + auto tile_type = device_ctx.grid[i][j].type; + logical_block_type = pick_logical_type(tile_type); + + g->set_color(block_color); + /* Get coords of current sub_tile */ + ezgl::rectangle abs_clb_bbox = draw_coords->get_absolute_clb_bbox(i, j, k, + logical_block_type); + ezgl::point2d center = abs_clb_bbox.center(); + + g->fill_rectangle(abs_clb_bbox); + + g->set_color(ezgl::BLACK); + + g->set_line_dash( + (EMPTY_BLOCK_ID == bnum) ? ezgl::line_dash::asymmetric_5_3 : ezgl::line_dash::none); + if (draw_state->draw_block_outlines) { + g->draw_rectangle(abs_clb_bbox); + } -static void drawnets(ezgl::renderer *g) { - t_draw_state *draw_state = get_draw_state_vars(); - t_draw_coords *draw_coords = get_draw_coords_vars(); - /* 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. */ - - ClusterBlockId b1, b2; - auto &cluster_ctx = g_vpr_ctx.clustering(); - - float NET_ALPHA = draw_state->net_alpha; - - g->set_line_dash(ezgl::line_dash::none); - g->set_line_width(0); - - /* Draw the net as a star from the source to each sink. Draw from centers of * - * blocks (or sub blocks in the case of IOs). */ - - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) - continue; /* Don't draw */ - - g->set_color(draw_state->net_color[net_id], - draw_state->net_color[net_id].alpha * NET_ALPHA); - b1 = cluster_ctx.clb_nlist.net_driver_block(net_id); - ezgl::point2d driver_center = draw_coords->get_absolute_clb_bbox(b1, - cluster_ctx.clb_nlist.block_type(b1)).center(); - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - b2 = cluster_ctx.clb_nlist.pin_block(pin_id); - ezgl::point2d sink_center = draw_coords->get_absolute_clb_bbox(b2, - cluster_ctx.clb_nlist.block_type(b2)).center(); - g->draw_line(driver_center, sink_center); - /* Uncomment to draw a chain instead of a star. */ - /* driver_center = sink_center; */ - } - } + if (draw_state->draw_block_text) { + /* Draw text if the space has parts of the netlist */ + if (bnum != EMPTY_BLOCK_ID && bnum != INVALID_BLOCK_ID) { + std::string name = cluster_ctx.clb_nlist.block_name( + bnum) + + vtr::string_fmt(" (#%zu)", size_t(bnum)); + + g->draw_text(center, name.c_str(), abs_clb_bbox.width(), + abs_clb_bbox.height()); + } + /* Draw text for block type so that user knows what block */ + if (device_ctx.grid[i][j].width_offset == 0 + && device_ctx.grid[i][j].height_offset == 0) { + std::string block_type_loc = device_ctx.grid[i][j].type->name; + block_type_loc += vtr::string_fmt(" (%d,%d)", i, j); + + g->draw_text( + center + - ezgl::point2d(0, + abs_clb_bbox.height() / 4), + block_type_loc.c_str(), abs_clb_bbox.width(), + abs_clb_bbox.height()); + } + } + } + } + } } +static void drawnets(ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + t_draw_coords* draw_coords = get_draw_coords_vars(); + /* 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. */ + + ClusterBlockId b1, b2; + auto& cluster_ctx = g_vpr_ctx.clustering(); + + float NET_ALPHA = draw_state->net_alpha; + + g->set_line_dash(ezgl::line_dash::none); + g->set_line_width(0); + + /* Draw the net as a star from the source to each sink. Draw from centers of * + * blocks (or sub blocks in the case of IOs). */ + + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + continue; /* Don't draw */ + + g->set_color(draw_state->net_color[net_id], + draw_state->net_color[net_id].alpha * NET_ALPHA); + b1 = cluster_ctx.clb_nlist.net_driver_block(net_id); + ezgl::point2d driver_center = draw_coords->get_absolute_clb_bbox(b1, + cluster_ctx.clb_nlist.block_type(b1)) + .center(); + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + b2 = cluster_ctx.clb_nlist.pin_block(pin_id); + ezgl::point2d sink_center = draw_coords->get_absolute_clb_bbox(b2, + cluster_ctx.clb_nlist.block_type(b2)) + .center(); + g->draw_line(driver_center, sink_center); + /* Uncomment to draw a chain instead of a star. */ + /* driver_center = sink_center; */ + } + } +} static void draw_congestion(ezgl::renderer* g) { /* Draws all the overused routing resources (i.e. congestion) in various contrasting colors showing congestion ratio. */ @@ -1322,161 +1288,160 @@ static void draw_congestion(ezgl::renderer* g) { draw_state->color_map = std::move(cmap); } -static void draw_routing_costs(ezgl::renderer *g) { - /* Draws routing resource nodes colored according to their congestion costs */ - - t_draw_state *draw_state = get_draw_state_vars(); - - /* show_routing_costs controls whether the total/sum of the costs or individual - * cost components (base cost, accumulated cost, present cost) are shown, and - * whether colours are proportional to the node's cost or the logarithm of - * it's cost.*/ - if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { - return; - } - - auto &device_ctx = g_vpr_ctx.device(); - auto &route_ctx = g_vpr_ctx.routing(); - g->set_line_width(0); - - VTR_ASSERT(!route_ctx.rr_node_route_inf.empty()); - - float min_cost = std::numeric_limits::infinity(); - float max_cost = -min_cost; - std::vector rr_node_costs(device_ctx.rr_nodes.size(), 0.); - - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - float cost = 0.; - if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS - || draw_state->show_routing_costs - == DRAW_LOG_TOTAL_ROUTING_COSTS) { - cost = get_single_rr_cong_cost(inode, - get_draw_state_vars()->pres_fac); - - } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { - cost = get_single_rr_cong_base_cost(inode); - - } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS - || draw_state->show_routing_costs - == DRAW_LOG_ACC_ROUTING_COSTS) { - cost = get_single_rr_cong_acc_cost(inode); - - } else { - VTR_ASSERT( - draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS - || draw_state->show_routing_costs - == DRAW_LOG_PRES_ROUTING_COSTS); - cost = get_single_rr_cong_pres_cost(inode, - get_draw_state_vars()->pres_fac); - } - - if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS - || draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS - || draw_state->show_routing_costs - == DRAW_LOG_PRES_ROUTING_COSTS) { - cost = std::log(cost); - } - rr_node_costs[inode] = cost; - min_cost = std::min(min_cost, cost); - max_cost = std::max(max_cost, cost); - } - - //Hide min value, draw_rr_costs() ignores NaN's - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - if (rr_node_costs[inode] == min_cost) { - rr_node_costs[inode] = NAN; - } - } - char msg[vtr::bufsize]; - if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS) { - sprintf(msg, "Total Congestion Cost Range [%g, %g]", min_cost, - max_cost); - } else if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS) { - sprintf(msg, "Log Total Congestion Cost Range [%g, %g]", min_cost, - max_cost); - } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { - sprintf(msg, "Base Congestion Cost Range [%g, %g]", min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS) { - sprintf(msg, "Accumulated (Historical) Congestion Cost Range [%g, %g]", - min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS) { - sprintf(msg, - "Log Accumulated (Historical) Congestion Cost Range [%g, %g]", - min_cost, max_cost); - } else if (draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS) { - sprintf(msg, "Present Congestion Cost Range [%g, %g]", min_cost, - max_cost); - } else if (draw_state->show_routing_costs == DRAW_LOG_PRES_ROUTING_COSTS) { - sprintf(msg, "Log Present Congestion Cost Range [%g, %g]", min_cost, - max_cost); - } else { - sprintf(msg, "Cost Range [%g, %g]", min_cost, max_cost); - } - application.update_message(msg); - - draw_rr_costs(g, rr_node_costs, true); -} +static void draw_routing_costs(ezgl::renderer* g) { + /* Draws routing resource nodes colored according to their congestion costs */ + + t_draw_state* draw_state = get_draw_state_vars(); + + /* show_routing_costs controls whether the total/sum of the costs or individual + * cost components (base cost, accumulated cost, present cost) are shown, and + * whether colours are proportional to the node's cost or the logarithm of + * it's cost.*/ + if (draw_state->show_routing_costs == DRAW_NO_ROUTING_COSTS) { + return; + } + + auto& device_ctx = g_vpr_ctx.device(); + auto& route_ctx = g_vpr_ctx.routing(); + g->set_line_width(0); + + VTR_ASSERT(!route_ctx.rr_node_route_inf.empty()); + + float min_cost = std::numeric_limits::infinity(); + float max_cost = -min_cost; + std::vector rr_node_costs(device_ctx.rr_nodes.size(), 0.); + + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + float cost = 0.; + if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_TOTAL_ROUTING_COSTS) { + cost = get_single_rr_cong_cost(inode, + get_draw_state_vars()->pres_fac); + + } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { + cost = get_single_rr_cong_base_cost(inode); + + } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_ACC_ROUTING_COSTS) { + cost = get_single_rr_cong_acc_cost(inode); + + } else { + VTR_ASSERT( + draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_PRES_ROUTING_COSTS); + cost = get_single_rr_cong_pres_cost(inode, + get_draw_state_vars()->pres_fac); + } + + if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS + || draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS + || draw_state->show_routing_costs + == DRAW_LOG_PRES_ROUTING_COSTS) { + cost = std::log(cost); + } + rr_node_costs[inode] = cost; + min_cost = std::min(min_cost, cost); + max_cost = std::max(max_cost, cost); + } + + //Hide min value, draw_rr_costs() ignores NaN's + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + if (rr_node_costs[inode] == min_cost) { + rr_node_costs[inode] = NAN; + } + } + char msg[vtr::bufsize]; + if (draw_state->show_routing_costs == DRAW_TOTAL_ROUTING_COSTS) { + sprintf(msg, "Total Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else if (draw_state->show_routing_costs == DRAW_LOG_TOTAL_ROUTING_COSTS) { + sprintf(msg, "Log Total Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else if (draw_state->show_routing_costs == DRAW_BASE_ROUTING_COSTS) { + sprintf(msg, "Base Congestion Cost Range [%g, %g]", min_cost, max_cost); + } else if (draw_state->show_routing_costs == DRAW_ACC_ROUTING_COSTS) { + sprintf(msg, "Accumulated (Historical) Congestion Cost Range [%g, %g]", + min_cost, max_cost); + } else if (draw_state->show_routing_costs == DRAW_LOG_ACC_ROUTING_COSTS) { + sprintf(msg, + "Log Accumulated (Historical) Congestion Cost Range [%g, %g]", + min_cost, max_cost); + } else if (draw_state->show_routing_costs == DRAW_PRES_ROUTING_COSTS) { + sprintf(msg, "Present Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else if (draw_state->show_routing_costs == DRAW_LOG_PRES_ROUTING_COSTS) { + sprintf(msg, "Log Present Congestion Cost Range [%g, %g]", min_cost, + max_cost); + } else { + sprintf(msg, "Cost Range [%g, %g]", min_cost, max_cost); + } + application.update_message(msg); -static void draw_routing_bb(ezgl::renderer *g) { - t_draw_state *draw_state = get_draw_state_vars(); - - if (draw_state->show_routing_bb == OPEN) { - return; - } - - auto &route_ctx = g_vpr_ctx.routing(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - - VTR_ASSERT(draw_state->show_routing_bb != OPEN); - VTR_ASSERT(draw_state->show_routing_bb < (int )route_ctx.route_bb.size()); - - t_draw_coords *draw_coords = get_draw_coords_vars(); - - auto net_id = ClusterNetId(draw_state->show_routing_bb); - const t_bb *bb = &route_ctx.route_bb[net_id]; - - //The router considers an RR node to be 'within' the the bounding box if it - //is *loosely* greater (i.e. greater than or equal) the left/bottom edges, and - //it is *loosely* less (i.e. less than or equal) the right/top edges. - // - //In the graphics we represent this by drawing the BB so that legal RR node start/end points - //are contained within the drawn box. Since VPR associates each x/y channel location to - //the right/top of the tile with the same x/y cordinates, this means we draw the box so that: - // * The left edge is to the left of the channel at bb xmin (including the channel at xmin) - // * The bottom edge is to the below of the channel at bb ymin (including the channel at ymin) - // * The right edge is to the right of the channel at bb xmax (including the channel at xmax) - // * The top edge is to the right of the channel at bb ymax (including the channel at ymax) - //Since tile_x/tile_y correspond to the drawing coordinates the block at grid x/y's bottom-left corner - //this means we need to shift the top/right drawn co-ordinate one tile + channel width right/up so - //the drawn box contains the top/right channels - double draw_xlow = draw_coords->tile_x[bb->xmin]; - double draw_ylow = draw_coords->tile_y[bb->ymin]; - double draw_xhigh = draw_coords->tile_x[bb->xmax] - + 2 * draw_coords->get_tile_width(); - double draw_yhigh = draw_coords->tile_y[bb->ymax] - + 2 * draw_coords->get_tile_height(); - - g->set_color(blk_RED); - g->draw_rectangle( { draw_xlow, draw_ylow }, { draw_xhigh, draw_yhigh }); - - ezgl::color fill = blk_SKYBLUE; - fill.alpha *= 0.3; - g->set_color(fill); - g->fill_rectangle( { draw_xlow, draw_ylow }, { draw_xhigh, draw_yhigh }); - - draw_routed_net(net_id, g); - - std::string msg; - msg += "Showing BB"; - msg += " (" + std::to_string(bb->xmin) + ", " + std::to_string(bb->ymin) - + ", " + std::to_string(bb->xmax) + ", " + std::to_string(bb->ymax) - + ")"; - msg += " and routing for net '" + cluster_ctx.clb_nlist.net_name(net_id) - + "'"; - msg += " (#" + std::to_string(size_t(net_id)) + ")"; - application.update_message(msg.c_str()); + draw_rr_costs(g, rr_node_costs, true); } +static void draw_routing_bb(ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + + if (draw_state->show_routing_bb == OPEN) { + return; + } + + auto& route_ctx = g_vpr_ctx.routing(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + + VTR_ASSERT(draw_state->show_routing_bb != OPEN); + VTR_ASSERT(draw_state->show_routing_bb < (int)route_ctx.route_bb.size()); + + t_draw_coords* draw_coords = get_draw_coords_vars(); + + auto net_id = ClusterNetId(draw_state->show_routing_bb); + const t_bb* bb = &route_ctx.route_bb[net_id]; + + //The router considers an RR node to be 'within' the the bounding box if it + //is *loosely* greater (i.e. greater than or equal) the left/bottom edges, and + //it is *loosely* less (i.e. less than or equal) the right/top edges. + // + //In the graphics we represent this by drawing the BB so that legal RR node start/end points + //are contained within the drawn box. Since VPR associates each x/y channel location to + //the right/top of the tile with the same x/y cordinates, this means we draw the box so that: + // * The left edge is to the left of the channel at bb xmin (including the channel at xmin) + // * The bottom edge is to the below of the channel at bb ymin (including the channel at ymin) + // * The right edge is to the right of the channel at bb xmax (including the channel at xmax) + // * The top edge is to the right of the channel at bb ymax (including the channel at ymax) + //Since tile_x/tile_y correspond to the drawing coordinates the block at grid x/y's bottom-left corner + //this means we need to shift the top/right drawn co-ordinate one tile + channel width right/up so + //the drawn box contains the top/right channels + double draw_xlow = draw_coords->tile_x[bb->xmin]; + double draw_ylow = draw_coords->tile_y[bb->ymin]; + double draw_xhigh = draw_coords->tile_x[bb->xmax] + + 2 * draw_coords->get_tile_width(); + double draw_yhigh = draw_coords->tile_y[bb->ymax] + + 2 * draw_coords->get_tile_height(); + + g->set_color(blk_RED); + g->draw_rectangle({draw_xlow, draw_ylow}, {draw_xhigh, draw_yhigh}); + + ezgl::color fill = blk_SKYBLUE; + fill.alpha *= 0.3; + g->set_color(fill); + g->fill_rectangle({draw_xlow, draw_ylow}, {draw_xhigh, draw_yhigh}); + + draw_routed_net(net_id, g); + + std::string msg; + msg += "Showing BB"; + msg += " (" + std::to_string(bb->xmin) + ", " + std::to_string(bb->ymin) + + ", " + std::to_string(bb->xmax) + ", " + std::to_string(bb->ymax) + + ")"; + msg += " and routing for net '" + cluster_ctx.clb_nlist.net_name(net_id) + + "'"; + msg += " (#" + std::to_string(size_t(net_id)) + ")"; + application.update_message(msg.c_str()); +} void draw_rr(ezgl::renderer* g) { /* Draws the routing resources that exist in the FPGA, if the user wants * @@ -1942,270 +1907,266 @@ static void draw_rr_edges(int inode, ezgl::renderer* g) { } /* End of for each edge loop */ } -static void draw_x(float x, float y, float size, ezgl::renderer *g) { - /* Draws an X centered at (x,y). The width and height of the X are each * - * 2 * size. */ - g->draw_line( { x - size, y + size }, { x + size, y - size }); - g->draw_line( { x - size, y - size }, { x + size, y + size }); +static void draw_x(float x, float y, float size, ezgl::renderer* g) { + /* Draws an X centered at (x,y). The width and height of the X are each * + * 2 * size. */ + g->draw_line({x - size, y + size}, {x + size, y - size}); + g->draw_line({x - size, y - size}, {x + size, y + size}); } -static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, - int chany_node, int chany_track, enum e_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(); - - /* Draws an edge (SBOX connection) between an x-directed channel and a * - * y-directed channel. */ - - float x1, y1, x2, y2; - ezgl::rectangle chanx_bbox; - ezgl::rectangle chany_bbox; - int chanx_xlow, chany_x, chany_ylow, chanx_y; - - /* Get the coordinates of the CHANX and CHANY segments. */ - chanx_bbox = draw_get_rr_chan_bbox(chanx_node); - chany_bbox = draw_get_rr_chan_bbox(chany_node); - - /* (x1,y1): point on CHANX segment, (x2,y2): point on CHANY segment. */ - - y1 = chanx_bbox.bottom(); - x2 = chany_bbox.left(); - - chanx_xlow = device_ctx.rr_nodes[chanx_node].xlow(); - chanx_y = device_ctx.rr_nodes[chanx_node].ylow(); - chany_x = device_ctx.rr_nodes[chany_node].xlow(); - chany_ylow = device_ctx.rr_nodes[chany_node].ylow(); - - if (chanx_xlow <= chany_x) { /* Can draw connection going right */ - /* Connection not at end of the CHANX segment. */ - x1 = draw_coords->tile_x[chany_x] + draw_coords->get_tile_width(); - - if (device_ctx.rr_nodes[chanx_node].direction() != BI_DIRECTION) { - if (edge_dir == FROM_X_TO_Y) { - if ((chanx_track % 2) == 1) { /* If dec wire, then going left */ - x1 = draw_coords->tile_x[chany_x + 1]; - } - } - } - - } else { /* Must draw connection going left. */ - x1 = chanx_bbox.left(); - } - - if (chany_ylow <= chanx_y) { /* Can draw connection going up. */ - /* Connection not at end of the CHANY segment. */ - y2 = draw_coords->tile_y[chanx_y] + draw_coords->get_tile_width(); - - if (device_ctx.rr_nodes[chany_node].direction() != BI_DIRECTION) { - if (edge_dir == FROM_Y_TO_X) { - if ((chany_track % 2) == 1) { /* If dec wire, then going down */ - y2 = draw_coords->tile_y[chanx_y + 1]; - } - } - } - - } else { /* Must draw connection going down. */ - y2 = chany_bbox.bottom(); - } - - g->draw_line( { x1, y1 }, { x2, y2 }); - - if (draw_state->draw_rr_toggle == DRAW_ALL_RR - || draw_state->draw_rr_node[chanx_node].node_highlighted) { - if (edge_dir == FROM_X_TO_Y) { - draw_rr_switch(x1, y1, x2, y2, - device_ctx.rr_switch_inf[switch_type].buffered(), - device_ctx.rr_switch_inf[switch_type].configurable(), g); - } else { - draw_rr_switch(x2, y2, x1, y1, - device_ctx.rr_switch_inf[switch_type].buffered(), - device_ctx.rr_switch_inf[switch_type].configurable(), g); - } - } +static void draw_chanx_to_chany_edge(int chanx_node, int chanx_track, int chany_node, int chany_track, enum e_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(); + + /* Draws an edge (SBOX connection) between an x-directed channel and a * + * y-directed channel. */ + + float x1, y1, x2, y2; + ezgl::rectangle chanx_bbox; + ezgl::rectangle chany_bbox; + int chanx_xlow, chany_x, chany_ylow, chanx_y; + + /* Get the coordinates of the CHANX and CHANY segments. */ + chanx_bbox = draw_get_rr_chan_bbox(chanx_node); + chany_bbox = draw_get_rr_chan_bbox(chany_node); + + /* (x1,y1): point on CHANX segment, (x2,y2): point on CHANY segment. */ + + y1 = chanx_bbox.bottom(); + x2 = chany_bbox.left(); + + chanx_xlow = device_ctx.rr_nodes[chanx_node].xlow(); + chanx_y = device_ctx.rr_nodes[chanx_node].ylow(); + chany_x = device_ctx.rr_nodes[chany_node].xlow(); + chany_ylow = device_ctx.rr_nodes[chany_node].ylow(); + + if (chanx_xlow <= chany_x) { /* Can draw connection going right */ + /* Connection not at end of the CHANX segment. */ + x1 = draw_coords->tile_x[chany_x] + draw_coords->get_tile_width(); + + if (device_ctx.rr_nodes[chanx_node].direction() != BI_DIRECTION) { + if (edge_dir == FROM_X_TO_Y) { + if ((chanx_track % 2) == 1) { /* If dec wire, then going left */ + x1 = draw_coords->tile_x[chany_x + 1]; + } + } + } + + } else { /* Must draw connection going left. */ + x1 = chanx_bbox.left(); + } + + if (chany_ylow <= chanx_y) { /* Can draw connection going up. */ + /* Connection not at end of the CHANY segment. */ + y2 = draw_coords->tile_y[chanx_y] + draw_coords->get_tile_width(); + + if (device_ctx.rr_nodes[chany_node].direction() != BI_DIRECTION) { + if (edge_dir == FROM_Y_TO_X) { + if ((chany_track % 2) == 1) { /* If dec wire, then going down */ + y2 = draw_coords->tile_y[chanx_y + 1]; + } + } + } + + } else { /* Must draw connection going down. */ + y2 = chany_bbox.bottom(); + } + + g->draw_line({x1, y1}, {x2, y2}); + + if (draw_state->draw_rr_toggle == DRAW_ALL_RR + || draw_state->draw_rr_node[chanx_node].node_highlighted) { + if (edge_dir == FROM_X_TO_Y) { + draw_rr_switch(x1, y1, x2, y2, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } else { + draw_rr_switch(x2, y2, x1, y1, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } + } } -static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, - short switch_type, ezgl::renderer *g) { - /* Draws a connection between two x-channel segments. Passing in the track * - * numbers allows this routine to be used for both rr_graph and routing * - * drawing-> */ - - 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(); - - float x1, x2, y1, y2; - ezgl::rectangle from_chan; - ezgl::rectangle to_chan; - int from_xlow, to_xlow, from_xhigh, to_xhigh; - - // Get the coordinates of the channel wires. - from_chan = draw_get_rr_chan_bbox(from_node); - to_chan = draw_get_rr_chan_bbox(to_node); - - /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ - - y1 = from_chan.bottom(); - y2 = to_chan.bottom(); - - from_xlow = device_ctx.rr_nodes[from_node].xlow(); - from_xhigh = device_ctx.rr_nodes[from_node].xhigh(); - to_xlow = device_ctx.rr_nodes[to_node].xlow(); - to_xhigh = device_ctx.rr_nodes[to_node].xhigh(); - if (to_xhigh < from_xlow) { /* From right to left */ - /* UDSD Note by WMF: could never happen for INC wires, unless U-turn. For DEC - * wires this handles well */ - x1 = from_chan.left(); - x2 = to_chan.right(); - } else if (to_xlow > from_xhigh) { /* From left to right */ - /* UDSD Note by WMF: could never happen for DEC wires, unless U-turn. For INC - * wires this handles well */ - x1 = from_chan.right(); - x2 = to_chan.left(); - } - - /* Segments overlap in the channel. Figure out best way to draw. Have to * - * make sure the drawing is symmetric in the from rr and to rr so the edges * - * will be drawn on top of each other for bidirectional connections. */ - - else { - if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { - /* must connect to to_node's wire beginning at x2 */ - if (to_track % 2 == 0) { /* INC wire starts at leftmost edge */ - VTR_ASSERT(from_xlow < to_xlow); - x2 = to_chan.left(); - /* since no U-turns from_track must be INC as well */ - x1 = draw_coords->tile_x[to_xlow - 1] - + draw_coords->get_tile_width(); - } else { /* DEC wire starts at rightmost edge */ - VTR_ASSERT(from_xhigh > to_xhigh); - x2 = to_chan.right(); - x1 = draw_coords->tile_x[to_xhigh + 1]; - } - } else { - if (to_xlow < from_xlow) { /* Draw from left edge of one to other */ - x1 = from_chan.left(); - x2 = draw_coords->tile_x[from_xlow - 1] - + draw_coords->get_tile_width(); - } else if (from_xlow < to_xlow) { - x1 = draw_coords->tile_x[to_xlow - 1] - + draw_coords->get_tile_width(); - x2 = to_chan.left(); - - } /* The following then is executed when from_xlow == to_xlow */ - else if (to_xhigh > from_xhigh) { /* Draw from right edge of one to other */ - x1 = from_chan.right(); - x2 = draw_coords->tile_x[from_xhigh + 1]; - } else if (from_xhigh > to_xhigh) { - x1 = draw_coords->tile_x[to_xhigh + 1]; - x2 = to_chan.right(); - } else { /* Complete overlap: start and end both align. Draw outside the sbox */ - x1 = from_chan.left(); - x2 = from_chan.left() + draw_coords->get_tile_width(); - } - } - } - - g->draw_line( { x1, y1 }, { x2, y2 }); - - if (draw_state->draw_rr_toggle == DRAW_ALL_RR - || draw_state->draw_rr_node[from_node].node_highlighted) { - draw_rr_switch(x1, y1, x2, y2, - device_ctx.rr_switch_inf[switch_type].buffered(), - device_ctx.rr_switch_inf[switch_type].configurable(), g); - } +static void draw_chanx_to_chanx_edge(int from_node, int to_node, int to_track, short switch_type, ezgl::renderer* g) { + /* Draws a connection between two x-channel segments. Passing in the track * + * numbers allows this routine to be used for both rr_graph and routing * + * drawing-> */ + + 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(); + + float x1, x2, y1, y2; + ezgl::rectangle from_chan; + ezgl::rectangle to_chan; + int from_xlow, to_xlow, from_xhigh, to_xhigh; + + // Get the coordinates of the channel wires. + from_chan = draw_get_rr_chan_bbox(from_node); + to_chan = draw_get_rr_chan_bbox(to_node); + + /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ + + y1 = from_chan.bottom(); + y2 = to_chan.bottom(); + + from_xlow = device_ctx.rr_nodes[from_node].xlow(); + from_xhigh = device_ctx.rr_nodes[from_node].xhigh(); + to_xlow = device_ctx.rr_nodes[to_node].xlow(); + to_xhigh = device_ctx.rr_nodes[to_node].xhigh(); + if (to_xhigh < from_xlow) { /* From right to left */ + /* UDSD Note by WMF: could never happen for INC wires, unless U-turn. For DEC + * wires this handles well */ + x1 = from_chan.left(); + x2 = to_chan.right(); + } else if (to_xlow > from_xhigh) { /* From left to right */ + /* UDSD Note by WMF: could never happen for DEC wires, unless U-turn. For INC + * wires this handles well */ + x1 = from_chan.right(); + x2 = to_chan.left(); + } + + /* Segments overlap in the channel. Figure out best way to draw. Have to * + * make sure the drawing is symmetric in the from rr and to rr so the edges * + * will be drawn on top of each other for bidirectional connections. */ + + else { + if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { + /* must connect to to_node's wire beginning at x2 */ + if (to_track % 2 == 0) { /* INC wire starts at leftmost edge */ + VTR_ASSERT(from_xlow < to_xlow); + x2 = to_chan.left(); + /* since no U-turns from_track must be INC as well */ + x1 = draw_coords->tile_x[to_xlow - 1] + + draw_coords->get_tile_width(); + } else { /* DEC wire starts at rightmost edge */ + VTR_ASSERT(from_xhigh > to_xhigh); + x2 = to_chan.right(); + x1 = draw_coords->tile_x[to_xhigh + 1]; + } + } else { + if (to_xlow < from_xlow) { /* Draw from left edge of one to other */ + x1 = from_chan.left(); + x2 = draw_coords->tile_x[from_xlow - 1] + + draw_coords->get_tile_width(); + } else if (from_xlow < to_xlow) { + x1 = draw_coords->tile_x[to_xlow - 1] + + draw_coords->get_tile_width(); + x2 = to_chan.left(); + + } /* The following then is executed when from_xlow == to_xlow */ + else if (to_xhigh > from_xhigh) { /* Draw from right edge of one to other */ + x1 = from_chan.right(); + x2 = draw_coords->tile_x[from_xhigh + 1]; + } else if (from_xhigh > to_xhigh) { + x1 = draw_coords->tile_x[to_xhigh + 1]; + x2 = to_chan.right(); + } else { /* Complete overlap: start and end both align. Draw outside the sbox */ + x1 = from_chan.left(); + x2 = from_chan.left() + draw_coords->get_tile_width(); + } + } + } + + g->draw_line({x1, y1}, {x2, y2}); + + if (draw_state->draw_rr_toggle == DRAW_ALL_RR + || draw_state->draw_rr_node[from_node].node_highlighted) { + draw_rr_switch(x1, y1, x2, y2, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } } -static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, - 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(); - - /* Draws a connection between two y-channel segments. Passing in the track * - * numbers allows this routine to be used for both rr_graph and routing * - * drawing-> */ - - float x1, x2, y1, y2; - ezgl::rectangle from_chan; - ezgl::rectangle to_chan; - int from_ylow, to_ylow, from_yhigh, to_yhigh; //, from_x, to_x; - - // Get the coordinates of the channel wires. - from_chan = draw_get_rr_chan_bbox(from_node); - to_chan = draw_get_rr_chan_bbox(to_node); - - // from_x = device_ctx.rr_nodes[from_node].xlow(); - // to_x = device_ctx.rr_nodes[to_node].xlow(); - from_ylow = device_ctx.rr_nodes[from_node].ylow(); - from_yhigh = device_ctx.rr_nodes[from_node].yhigh(); - to_ylow = device_ctx.rr_nodes[to_node].ylow(); - to_yhigh = device_ctx.rr_nodes[to_node].yhigh(); - - /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ - - x1 = from_chan.left(); - x2 = to_chan.left(); - - if (to_yhigh < from_ylow) { /* From upper to lower */ - y1 = from_chan.bottom(); - y2 = to_chan.top(); - } else if (to_ylow > from_yhigh) { /* From lower to upper */ - y1 = from_chan.top(); - y2 = to_chan.bottom(); - } - - /* Segments overlap in the channel. Figure out best way to draw. Have to * - * make sure the drawing is symmetric in the from rr and to rr so the edges * - * will be drawn on top of each other for bidirectional connections. */ - - /* UDSD Modification by WMF Begin */ - else { - if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { - if (to_track % 2 == 0) { /* INC wire starts at bottom edge */ - - y2 = to_chan.bottom(); - /* since no U-turns from_track must be INC as well */ - y1 = draw_coords->tile_y[to_ylow - 1] - + draw_coords->get_tile_width(); - } else { /* DEC wire starts at top edge */ - - y2 = to_chan.top(); - y1 = draw_coords->tile_y[to_yhigh + 1]; - } - } else { - if (to_ylow < from_ylow) { /* Draw from bottom edge of one to other. */ - y1 = from_chan.bottom(); - y2 = draw_coords->tile_y[from_ylow - 1] - + draw_coords->get_tile_width(); - } else if (from_ylow < to_ylow) { - y1 = draw_coords->tile_y[to_ylow - 1] - + draw_coords->get_tile_width(); - y2 = to_chan.bottom(); - } else if (to_yhigh > from_yhigh) { /* Draw from top edge of one to other. */ - y1 = from_chan.top(); - y2 = draw_coords->tile_y[from_yhigh + 1]; - } else if (from_yhigh > to_yhigh) { - y1 = draw_coords->tile_y[to_yhigh + 1]; - y2 = to_chan.top(); - } else { /* Complete overlap: start and end both align. Draw outside the sbox */ - y1 = from_chan.bottom(); - y2 = from_chan.bottom() + draw_coords->get_tile_width(); - } - } - } - - /* UDSD Modification by WMF End */ - g->draw_line( { x1, y1 }, { x2, y2 }); - - if (draw_state->draw_rr_toggle == DRAW_ALL_RR - || draw_state->draw_rr_node[from_node].node_highlighted) { - draw_rr_switch(x1, y1, x2, y2, - device_ctx.rr_switch_inf[switch_type].buffered(), - device_ctx.rr_switch_inf[switch_type].configurable(), g); - } +static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, 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(); + + /* Draws a connection between two y-channel segments. Passing in the track * + * numbers allows this routine to be used for both rr_graph and routing * + * drawing-> */ + + float x1, x2, y1, y2; + ezgl::rectangle from_chan; + ezgl::rectangle to_chan; + int from_ylow, to_ylow, from_yhigh, to_yhigh; //, from_x, to_x; + + // Get the coordinates of the channel wires. + from_chan = draw_get_rr_chan_bbox(from_node); + to_chan = draw_get_rr_chan_bbox(to_node); + + // from_x = device_ctx.rr_nodes[from_node].xlow(); + // to_x = device_ctx.rr_nodes[to_node].xlow(); + from_ylow = device_ctx.rr_nodes[from_node].ylow(); + from_yhigh = device_ctx.rr_nodes[from_node].yhigh(); + to_ylow = device_ctx.rr_nodes[to_node].ylow(); + to_yhigh = device_ctx.rr_nodes[to_node].yhigh(); + + /* (x1, y1) point on from_node, (x2, y2) point on to_node. */ + + x1 = from_chan.left(); + x2 = to_chan.left(); + + if (to_yhigh < from_ylow) { /* From upper to lower */ + y1 = from_chan.bottom(); + y2 = to_chan.top(); + } else if (to_ylow > from_yhigh) { /* From lower to upper */ + y1 = from_chan.top(); + y2 = to_chan.bottom(); + } + + /* Segments overlap in the channel. Figure out best way to draw. Have to * + * make sure the drawing is symmetric in the from rr and to rr so the edges * + * will be drawn on top of each other for bidirectional connections. */ + + /* UDSD Modification by WMF Begin */ + else { + if (device_ctx.rr_nodes[to_node].direction() != BI_DIRECTION) { + if (to_track % 2 == 0) { /* INC wire starts at bottom edge */ + + y2 = to_chan.bottom(); + /* since no U-turns from_track must be INC as well */ + y1 = draw_coords->tile_y[to_ylow - 1] + + draw_coords->get_tile_width(); + } else { /* DEC wire starts at top edge */ + + y2 = to_chan.top(); + y1 = draw_coords->tile_y[to_yhigh + 1]; + } + } else { + if (to_ylow < from_ylow) { /* Draw from bottom edge of one to other. */ + y1 = from_chan.bottom(); + y2 = draw_coords->tile_y[from_ylow - 1] + + draw_coords->get_tile_width(); + } else if (from_ylow < to_ylow) { + y1 = draw_coords->tile_y[to_ylow - 1] + + draw_coords->get_tile_width(); + y2 = to_chan.bottom(); + } else if (to_yhigh > from_yhigh) { /* Draw from top edge of one to other. */ + y1 = from_chan.top(); + y2 = draw_coords->tile_y[from_yhigh + 1]; + } else if (from_yhigh > to_yhigh) { + y1 = draw_coords->tile_y[to_yhigh + 1]; + y2 = to_chan.top(); + } else { /* Complete overlap: start and end both align. Draw outside the sbox */ + y1 = from_chan.bottom(); + y2 = from_chan.bottom() + draw_coords->get_tile_width(); + } + } + } + + /* UDSD Modification by WMF End */ + g->draw_line({x1, y1}, {x2, y2}); + + if (draw_state->draw_rr_toggle == DRAW_ALL_RR + || draw_state->draw_rr_node[from_node].node_highlighted) { + draw_rr_switch(x1, y1, x2, y2, + device_ctx.rr_switch_inf[switch_type].buffered(), + device_ctx.rr_switch_inf[switch_type].configurable(), g); + } } /* This function computes and returns the boundary coordinates of a channel @@ -2214,7 +2175,6 @@ static void draw_chany_to_chany_edge(int from_node, int to_node, int to_track, * TODO: Fix this for global routing, currently for detailed only. */ ezgl::rectangle draw_get_rr_chan_bbox(int inode) { - double left = 0, right = 0, top = 0, bottom = 0; t_draw_coords* draw_coords = get_draw_coords_vars(); auto& device_ctx = g_vpr_ctx.device(); @@ -2252,268 +2212,261 @@ ezgl::rectangle draw_get_rr_chan_bbox(int inode) { return bound_box; } -static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, - bool buffered, bool configurable, ezgl::renderer *g) { - /* 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. */ - - if (!buffered) { - if (configurable) { /* Draw a circle for a pass transistor */ - float xcen = from_x + (to_x - from_x) / 10.; - float ycen = from_y + (to_y - from_y) / 10.; - const float switch_rad = 0.15; - g->draw_arc( { xcen, ycen }, switch_rad, 0., 360.); - } else { - //Pass, nothing to draw - } - } else { /* Buffer */ - if (from_x == to_x || from_y == to_y) { - //Straight connection - draw_triangle_along_line(g, { from_x, from_y }, { to_x, to_y }, - SB_EDGE_STRAIGHT_ARROW_POSITION); - } else { - //Turn connection - draw_triangle_along_line(g, { from_x, from_y }, { to_x, to_y }, - SB_EDGE_TURN_ARROW_POSITION); - } - } +static void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, bool buffered, bool configurable, ezgl::renderer* g) { + /* 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. */ + + if (!buffered) { + if (configurable) { /* Draw a circle for a pass transistor */ + float xcen = from_x + (to_x - from_x) / 10.; + float ycen = from_y + (to_y - from_y) / 10.; + const float switch_rad = 0.15; + g->draw_arc({xcen, ycen}, switch_rad, 0., 360.); + } else { + //Pass, nothing to draw + } + } else { /* Buffer */ + if (from_x == to_x || from_y == to_y) { + //Straight connection + draw_triangle_along_line(g, {from_x, from_y}, {to_x, to_y}, + SB_EDGE_STRAIGHT_ARROW_POSITION); + } else { + //Turn connection + draw_triangle_along_line(g, {from_x, from_y}, {to_x, to_y}, + SB_EDGE_TURN_ARROW_POSITION); + } + } } -static void draw_rr_pin(int 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. */ - - t_draw_coords *draw_coords = get_draw_coords_vars(); - - float xcen, ycen; - char str[vtr::bufsize]; - auto &device_ctx = g_vpr_ctx.device(); - - int ipin = device_ctx.rr_nodes[inode].ptc_num(); - - g->set_color(color); - - /* TODO: This is where we can hide fringe physical pins and also identify globals (hide, color, show) */ - /* As nodes may appear on more than one side, walk through the possible nodes - * - draw the pin on each side that it appears - */ - for (const e_side &pin_side : SIDES) { - if (!device_ctx.rr_nodes[inode].is_node_on_specific_side(pin_side)) { - continue; - } - draw_get_rr_pin_coords(inode, &xcen, &ycen, pin_side); - g->fill_rectangle( - { xcen - draw_coords->pin_size, ycen - draw_coords->pin_size }, - { xcen + draw_coords->pin_size, ycen + draw_coords->pin_size }); - sprintf(str, "%d", ipin); - g->set_color(ezgl::BLACK); - g->draw_text( { xcen, ycen }, str, 2 * draw_coords->pin_size, - 2 * draw_coords->pin_size); - g->set_color(color); - } -} +static void draw_rr_pin(int 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. */ -/* Returns the coordinates at which the center of this pin should be drawn. * - * inode gives the node number, and iside gives the side of the clb or pad * - * the physical pin is on. */ -void draw_get_rr_pin_coords(int inode, float *xcen, float *ycen, - const e_side &pin_side) { - auto &device_ctx = g_vpr_ctx.device(); - draw_get_rr_pin_coords(device_ctx.rr_nodes[inode], xcen, ycen, pin_side); -} + t_draw_coords* draw_coords = get_draw_coords_vars(); -void draw_get_rr_pin_coords(const t_rr_node &node, float *xcen, float *ycen, - const e_side &pin_side) { - t_draw_coords *draw_coords = get_draw_coords_vars(); - - int i, j, k, ipin, pins_per_sub_tile; - float offset, xc, yc, step; - t_physical_tile_type_ptr type; - auto &device_ctx = g_vpr_ctx.device(); - - i = node.xlow(); - j = node.ylow(); - - xc = draw_coords->tile_x[i]; - yc = draw_coords->tile_y[j]; - - ipin = node.ptc_num(); - type = device_ctx.grid[i][j].type; - pins_per_sub_tile = type->num_pins / type->capacity; - k = ipin / pins_per_sub_tile; - - /* Since pins numbers go across all sub_tiles in a block in order - * we can treat as a block box for this step */ - - /* For each sub_tile we need and extra padding space */ - step = (float) (draw_coords->get_tile_width()) - / (float) (type->num_pins + type->capacity); - offset = (ipin + k + 1) * step; - - switch (pin_side) { - case LEFT: - yc += offset; - break; - - case RIGHT: - xc += draw_coords->get_tile_width(); - yc += offset; - break; - - case BOTTOM: - xc += offset; - break; - - case TOP: - xc += offset; - yc += draw_coords->get_tile_width(); - break; - - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in draw_get_rr_pin_coords: Unexpected side %s.\n", - SIDE_STRING[pin_side]); - break; - } - - *xcen = xc; - *ycen = yc; + float xcen, ycen; + char str[vtr::bufsize]; + auto& device_ctx = g_vpr_ctx.device(); + + int ipin = device_ctx.rr_nodes[inode].ptc_num(); + + g->set_color(color); + + /* TODO: This is where we can hide fringe physical pins and also identify globals (hide, color, show) */ + /* As nodes may appear on more than one side, walk through the possible nodes + * - draw the pin on each side that it appears + */ + for (const e_side& pin_side : SIDES) { + if (!device_ctx.rr_nodes[inode].is_node_on_specific_side(pin_side)) { + continue; + } + draw_get_rr_pin_coords(inode, &xcen, &ycen, pin_side); + g->fill_rectangle( + {xcen - draw_coords->pin_size, ycen - draw_coords->pin_size}, + {xcen + draw_coords->pin_size, ycen + draw_coords->pin_size}); + sprintf(str, "%d", ipin); + g->set_color(ezgl::BLACK); + g->draw_text({xcen, ycen}, str, 2 * draw_coords->pin_size, + 2 * draw_coords->pin_size); + g->set_color(color); + } +} + +/* Returns the coordinates at which the center of this pin should be drawn. * + * inode gives the node number, and iside gives the side of the clb or pad * + * the physical pin is on. */ +void draw_get_rr_pin_coords(int inode, float* xcen, float* ycen, const e_side& pin_side) { + auto& device_ctx = g_vpr_ctx.device(); + draw_get_rr_pin_coords(device_ctx.rr_nodes[inode], xcen, ycen, pin_side); +} + +void draw_get_rr_pin_coords(const t_rr_node& node, float* xcen, float* ycen, const e_side& pin_side) { + t_draw_coords* draw_coords = get_draw_coords_vars(); + + int i, j, k, ipin, pins_per_sub_tile; + float offset, xc, yc, step; + t_physical_tile_type_ptr type; + auto& device_ctx = g_vpr_ctx.device(); + + i = node.xlow(); + j = node.ylow(); + + xc = draw_coords->tile_x[i]; + yc = draw_coords->tile_y[j]; + + ipin = node.ptc_num(); + type = device_ctx.grid[i][j].type; + pins_per_sub_tile = type->num_pins / type->capacity; + k = ipin / pins_per_sub_tile; + + /* Since pins numbers go across all sub_tiles in a block in order + * we can treat as a block box for this step */ + + /* For each sub_tile we need and extra padding space */ + step = (float)(draw_coords->get_tile_width()) + / (float)(type->num_pins + type->capacity); + offset = (ipin + k + 1) * step; + + switch (pin_side) { + case LEFT: + yc += offset; + break; + + case RIGHT: + xc += draw_coords->get_tile_width(); + yc += offset; + break; + + case BOTTOM: + xc += offset; + break; + + case TOP: + xc += offset; + yc += draw_coords->get_tile_width(); + break; + + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in draw_get_rr_pin_coords: Unexpected side %s.\n", + SIDE_STRING[pin_side]); + break; + } + + *xcen = xc; + *ycen = yc; } -static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer *g) { - t_draw_coords *draw_coords = get_draw_coords_vars(); +static void draw_rr_src_sink(int inode, ezgl::color color, ezgl::renderer* g) { + t_draw_coords* draw_coords = get_draw_coords_vars(); - auto &device_ctx = g_vpr_ctx.device(); + auto& device_ctx = g_vpr_ctx.device(); - float xcen, ycen; - draw_get_rr_src_sink_coords(device_ctx.rr_nodes[inode], &xcen, &ycen); + float xcen, ycen; + draw_get_rr_src_sink_coords(device_ctx.rr_nodes[inode], &xcen, &ycen); - g->set_color(color); + g->set_color(color); - g->fill_rectangle( - { xcen - draw_coords->pin_size, ycen - draw_coords->pin_size }, - { xcen + draw_coords->pin_size, ycen + draw_coords->pin_size }); + g->fill_rectangle( + {xcen - draw_coords->pin_size, ycen - draw_coords->pin_size}, + {xcen + draw_coords->pin_size, ycen + draw_coords->pin_size}); - std::string str = vtr::string_fmt("%d", - device_ctx.rr_nodes[inode].ptc_num()); - g->set_color(ezgl::BLACK); - g->draw_text( { xcen, ycen }, str.c_str(), 2 * draw_coords->pin_size, - 2 * draw_coords->pin_size); - g->set_color(color); + std::string str = vtr::string_fmt("%d", + device_ctx.rr_nodes[inode].ptc_num()); + g->set_color(ezgl::BLACK); + g->draw_text({xcen, ycen}, str.c_str(), 2 * draw_coords->pin_size, + 2 * draw_coords->pin_size); + g->set_color(color); } -static void draw_get_rr_src_sink_coords(const t_rr_node &node, float *xcen, - float *ycen) { - t_draw_coords *draw_coords = get_draw_coords_vars(); +static void draw_get_rr_src_sink_coords(const t_rr_node& node, float* xcen, float* ycen) { + t_draw_coords* draw_coords = get_draw_coords_vars(); - auto &device_ctx = g_vpr_ctx.device(); - t_physical_tile_type_ptr tile_type = - device_ctx.grid[node.xlow()][node.ylow()].type; + auto& device_ctx = g_vpr_ctx.device(); + t_physical_tile_type_ptr tile_type = device_ctx.grid[node.xlow()][node.ylow()].type; - //Number of classes (i.e. src/sinks) we need to draw - float num_class = tile_type->class_inf.size(); + //Number of classes (i.e. src/sinks) we need to draw + float num_class = tile_type->class_inf.size(); - int height = tile_type->height; //Height in blocks + int height = tile_type->height; //Height in blocks - //How many classes to draw per unit block height - int class_per_height = num_class; - if (height > 1) { - class_per_height = num_class / (height - 1); - } + //How many classes to draw per unit block height + int class_per_height = num_class; + if (height > 1) { + class_per_height = num_class / (height - 1); + } - int class_height_offset = node.class_num() / class_per_height; //Offset wrt block height - int class_height_shift = node.class_num() % class_per_height; //Offset within unit block + int class_height_offset = node.class_num() / class_per_height; //Offset wrt block height + int class_height_shift = node.class_num() % class_per_height; //Offset within unit block - float xc = draw_coords->tile_x[node.xlow()]; - float yc = draw_coords->tile_y[node.ylow() + class_height_offset]; + float xc = draw_coords->tile_x[node.xlow()]; + float yc = draw_coords->tile_y[node.ylow() + class_height_offset]; - *xcen = xc + 0.5 * draw_coords->get_tile_width(); + *xcen = xc + 0.5 * draw_coords->get_tile_width(); - float class_section_height = class_per_height + 1; + float class_section_height = class_per_height + 1; - float ypos = (class_height_shift + 1) / class_section_height; - *ycen = yc + ypos * draw_coords->get_tile_height(); + float ypos = (class_height_shift + 1) / class_section_height; + *ycen = yc + ypos * draw_coords->get_tile_height(); } /* Draws the nets in the positions fixed by the router. If draw_net_type is * * ALL_NETS, draw all the nets. If it is HIGHLIGHTED, draw only the nets * * that are not coloured black (useful for drawing over the rr_graph). */ -static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer *g) { - /* Next free track in each channel segment if routing is GLOBAL */ +static void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer* g) { + /* Next free track in each channel segment if routing is GLOBAL */ - auto &cluster_ctx = g_vpr_ctx.clustering(); + auto& cluster_ctx = g_vpr_ctx.clustering(); - t_draw_state *draw_state = get_draw_state_vars(); + t_draw_state* draw_state = get_draw_state_vars(); - float NET_ALPHA = draw_state->net_alpha; + float NET_ALPHA = draw_state->net_alpha; - g->set_line_dash(ezgl::line_dash::none); - g->set_color(ezgl::BLACK, ezgl::BLACK.alpha * NET_ALPHA); + g->set_line_dash(ezgl::line_dash::none); + g->set_color(ezgl::BLACK, ezgl::BLACK.alpha * NET_ALPHA); - /* Now draw each net, one by one. */ + /* Now draw each net, one by one. */ - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - if (draw_net_type == HIGHLIGHTED - && draw_state->net_color[net_id] == ezgl::BLACK) - continue; + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + if (draw_net_type == HIGHLIGHTED + && draw_state->net_color[net_id] == ezgl::BLACK) + continue; - draw_routed_net(net_id, g); - } /* End for (each net) */ + draw_routed_net(net_id, g); + } /* End for (each net) */ } -static void draw_routed_net(ClusterNetId net_id, ezgl::renderer *g) { - auto &route_ctx = g_vpr_ctx.routing(); - auto &cluster_ctx = g_vpr_ctx.clustering(); +static void draw_routed_net(ClusterNetId 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(); + t_draw_state* draw_state = get_draw_state_vars(); - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) /* Don't draw. */ - return; + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) /* Don't draw. */ + return; - if (route_ctx.trace[net_id].head == nullptr) /* No routing-> Skip. (Allows me to draw */ - return; /* partially complete routes). */ + if (route_ctx.trace[net_id].head == nullptr) /* No routing-> Skip. (Allows me to draw */ + return; /* partially complete routes). */ - t_trace *tptr = route_ctx.trace[net_id].head; /* SOURCE to start */ - int inode = tptr->index; + t_trace* tptr = route_ctx.trace[net_id].head; /* SOURCE to start */ + int inode = tptr->index; - std::vector rr_nodes_to_draw; - rr_nodes_to_draw.push_back(inode); - for (;;) { - tptr = tptr->next; - inode = tptr->index; + std::vector rr_nodes_to_draw; + rr_nodes_to_draw.push_back(inode); + for (;;) { + tptr = tptr->next; + inode = tptr->index; - 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[net_id]; - draw_state->draw_rr_node[inode].node_highlighted = true; - } else { - /* If not highlighted, draw the node in default color. */ - draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; - } + 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[net_id]; + draw_state->draw_rr_node[inode].node_highlighted = true; + } else { + /* If not highlighted, draw the node in default color. */ + draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; + } - rr_nodes_to_draw.push_back(inode); + rr_nodes_to_draw.push_back(inode); - if (tptr->iswitch == OPEN) { //End of branch - draw_partial_route(rr_nodes_to_draw, g); - rr_nodes_to_draw.clear(); + if (tptr->iswitch == OPEN) { //End of branch + draw_partial_route(rr_nodes_to_draw, g); + rr_nodes_to_draw.clear(); - /* Skip the next segment */ - tptr = tptr->next; - if (tptr == nullptr) - break; - inode = tptr->index; - rr_nodes_to_draw.push_back(inode); - } + /* Skip the next segment */ + tptr = tptr->next; + if (tptr == nullptr) + break; + inode = tptr->index; + rr_nodes_to_draw.push_back(inode); + } - } /* End loop over traceback. */ + } /* End loop over traceback. */ - draw_partial_route(rr_nodes_to_draw, g); + draw_partial_route(rr_nodes_to_draw, g); } //Draws the set of rr_nodes specified, using the colors set in draw_state @@ -2644,37 +2597,36 @@ void draw_partial_route(const std::vector& rr_nodes_to_draw, ezgl::renderer } } -static 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. */ +static 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. */ int i, j; t_rr_type rr_type; auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - if (get_draw_state_vars()->draw_route_type == DETAILED) - return (device_ctx.rr_nodes[inode].ptc_num()); + if (get_draw_state_vars()->draw_route_type == DETAILED) + return (device_ctx.rr_nodes[inode].ptc_num()); - /* GLOBAL route stuff below. */ + /* GLOBAL route stuff below. */ rr_type = rr_graph.node_type(RRNodeId(inode)); i = device_ctx.rr_nodes[inode].xlow(); /* NB: Global rr graphs must have only unit */ j = device_ctx.rr_nodes[inode].ylow(); /* length channel segments. */ - switch (rr_type) { - case CHANX: - return (chanx_track[i][j]); + switch (rr_type) { + case CHANX: + return (chanx_track[i][j]); - case CHANY: - return (chany_track[i][j]); + case CHANY: + return (chany_track[i][j]); - default: - vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, - "in get_track_num: Unexpected node type %d for node %d.\n", - rr_type, inode); - return OPEN; - } + default: + vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__, + "in get_track_num: Unexpected node type %d for node %d.\n", + rr_type, inode); + return OPEN; + } } /* This helper function determines whether a net has been highlighted. The highlighting @@ -2682,46 +2634,45 @@ static int get_track_num(int inode, const vtr::OffsetMatrix &chanx_track, * fan-in/fan-out of a highlighted node. */ static bool draw_if_net_highlighted(ClusterNetId inet) { - t_draw_state *draw_state = get_draw_state_vars(); + t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->net_color[inet] != DEFAULT_RR_NODE_COLOR) { - return true; - } + if (draw_state->net_color[inet] != DEFAULT_RR_NODE_COLOR) { + return true; + } - return false; + return false; } /* 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, int hit_node) { - t_trace *tptr; - auto &cluster_ctx = g_vpr_ctx.clustering(); - 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()) { - for (tptr = route_ctx.trace[net_id].head; tptr != nullptr; - tptr = tptr->next) { - if (draw_state->draw_rr_node[tptr->index].color == ezgl::MAGENTA) { - draw_state->net_color[net_id] = - draw_state->draw_rr_node[tptr->index].color; - if (tptr->index == 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[tptr->index].color - == ezgl::WHITE) { - // If node is de-selected. - draw_state->net_color[net_id] = ezgl::BLACK; - break; - } - } - } - application.update_message(message); +void highlight_nets(char* message, int hit_node) { + t_trace* tptr; + auto& cluster_ctx = g_vpr_ctx.clustering(); + 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()) { + for (tptr = route_ctx.trace[net_id].head; tptr != nullptr; + tptr = tptr->next) { + if (draw_state->draw_rr_node[tptr->index].color == ezgl::MAGENTA) { + draw_state->net_color[net_id] = draw_state->draw_rr_node[tptr->index].color; + if (tptr->index == 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[tptr->index].color + == ezgl::WHITE) { + // If node is de-selected. + draw_state->net_color[net_id] = ezgl::BLACK; + break; + } + } + } + application.update_message(message); } /* If an rr_node has been clicked on, it will be either highlighted in MAGENTA, @@ -2729,56 +2680,52 @@ void highlight_nets(char *message, int hit_node) { * fan_in into the node in blue and fan_out from the node in red. If de-highlighted, * de-highlight its fan_in and fan_out. */ -void draw_highlight_fan_in_fan_out(const std::set &nodes) { - t_draw_state *draw_state = get_draw_state_vars(); - auto &device_ctx = g_vpr_ctx.device(); - - for (auto node : nodes) { - /* Highlight the fanout nodes in red. */ - for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[node].num_edges(); - iedge < l; iedge++) { - int fanout_node = device_ctx.rr_nodes[node].edge_sink_node(iedge); - - if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA - && draw_state->draw_rr_node[fanout_node].color - != ezgl::MAGENTA) { - // If node is highlighted, highlight its fanout - draw_state->draw_rr_node[fanout_node].color = DRIVES_IT_COLOR; - draw_state->draw_rr_node[fanout_node].node_highlighted = true; - } else if (draw_state->draw_rr_node[node].color == ezgl::WHITE) { - // If node is de-highlighted, de-highlight its fanout - draw_state->draw_rr_node[fanout_node].color = - DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[fanout_node].node_highlighted = false; - } - } - - /* Highlight the nodes that can fanin to this node in blue. */ - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { - for (t_edge_size iedge = 0, l = - device_ctx.rr_nodes[inode].num_edges(); iedge < l; - iedge++) { - int fanout_node = device_ctx.rr_nodes[inode].edge_sink_node( - iedge); - if (fanout_node == node) { - if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA - && draw_state->draw_rr_node[inode].color - != ezgl::MAGENTA) { - // If node is highlighted, highlight its fanin - draw_state->draw_rr_node[inode].color = ezgl::BLUE; - draw_state->draw_rr_node[inode].node_highlighted = true; - } else if (draw_state->draw_rr_node[node].color - == ezgl::WHITE) { - // If node is de-highlighted, de-highlight its fanin - draw_state->draw_rr_node[inode].color = - DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[inode].node_highlighted = - false; - } - } - } - } - } +void draw_highlight_fan_in_fan_out(const std::set& nodes) { + t_draw_state* draw_state = get_draw_state_vars(); + auto& device_ctx = g_vpr_ctx.device(); + + for (auto node : nodes) { + /* Highlight the fanout nodes in red. */ + for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[node].num_edges(); + iedge < l; iedge++) { + int fanout_node = device_ctx.rr_nodes[node].edge_sink_node(iedge); + + if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA + && draw_state->draw_rr_node[fanout_node].color + != ezgl::MAGENTA) { + // If node is highlighted, highlight its fanout + draw_state->draw_rr_node[fanout_node].color = DRIVES_IT_COLOR; + draw_state->draw_rr_node[fanout_node].node_highlighted = true; + } else if (draw_state->draw_rr_node[node].color == ezgl::WHITE) { + // If node is de-highlighted, de-highlight its fanout + draw_state->draw_rr_node[fanout_node].color = DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[fanout_node].node_highlighted = false; + } + } + + /* Highlight the nodes that can fanin to this node in blue. */ + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); inode++) { + for (t_edge_size iedge = 0, l = device_ctx.rr_nodes[inode].num_edges(); iedge < l; + iedge++) { + int fanout_node = device_ctx.rr_nodes[inode].edge_sink_node( + iedge); + if (fanout_node == node) { + if (draw_state->draw_rr_node[node].color == ezgl::MAGENTA + && draw_state->draw_rr_node[inode].color + != ezgl::MAGENTA) { + // If node is highlighted, highlight its fanin + draw_state->draw_rr_node[inode].color = ezgl::BLUE; + draw_state->draw_rr_node[inode].node_highlighted = true; + } else if (draw_state->draw_rr_node[node].color + == ezgl::WHITE) { + // If node is de-highlighted, de-highlight its fanin + draw_state->draw_rr_node[inode].color = DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[inode].node_highlighted = false; + } + } + } + } + } } /* This is a helper function for highlight_rr_nodes(). It determines whether @@ -2853,28 +2800,27 @@ static int draw_check_rr_node_hit(float click_x, float click_y) { } std::set draw_expand_non_configurable_rr_nodes(int from_node) { - std::set expanded_nodes; - draw_expand_non_configurable_rr_nodes_recurr(from_node, expanded_nodes); - return expanded_nodes; + std::set expanded_nodes; + draw_expand_non_configurable_rr_nodes_recurr(from_node, expanded_nodes); + return expanded_nodes; } void draw_expand_non_configurable_rr_nodes_recurr(int from_node, - std::set &expanded_nodes) { - auto &device_ctx = g_vpr_ctx.device(); - - expanded_nodes.insert(from_node); - - for (t_edge_size iedge = 0; - iedge < device_ctx.rr_nodes[from_node].num_edges(); ++iedge) { - bool edge_configurable = - device_ctx.rr_nodes[from_node].edge_is_configurable(iedge); - int to_node = device_ctx.rr_nodes[from_node].edge_sink_node(iedge); - - if (!edge_configurable && !expanded_nodes.count(to_node)) { - draw_expand_non_configurable_rr_nodes_recurr(to_node, - expanded_nodes); - } - } + std::set& expanded_nodes) { + auto& device_ctx = g_vpr_ctx.device(); + + expanded_nodes.insert(from_node); + + for (t_edge_size iedge = 0; + iedge < device_ctx.rr_nodes[from_node].num_edges(); ++iedge) { + bool edge_configurable = device_ctx.rr_nodes[from_node].edge_is_configurable(iedge); + int to_node = device_ctx.rr_nodes[from_node].edge_sink_node(iedge); + + if (!edge_configurable && !expanded_nodes.count(to_node)) { + draw_expand_non_configurable_rr_nodes_recurr(to_node, + expanded_nodes); + } + } } /* This routine is called when the routing resource graph is shown, and someone @@ -2883,18 +2829,18 @@ void draw_expand_non_configurable_rr_nodes_recurr(int from_node, * clicked upon, we highlight it in Magenta, and its fanout in red. */ static bool highlight_rr_nodes(float x, float y) { - t_draw_state *draw_state = get_draw_state_vars(); + t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->draw_rr_toggle == DRAW_NO_RR && !draw_state->show_nets) { - application.update_message(draw_state->default_message); - application.refresh_drawing(); - return false; //No rr shown - } + if (draw_state->draw_rr_toggle == DRAW_NO_RR && !draw_state->show_nets) { + application.update_message(draw_state->default_message); + application.refresh_drawing(); + return false; //No rr shown + } - // Check which rr_node (if any) was clicked on. - int hit_node = draw_check_rr_node_hit(x, y); + // Check which rr_node (if any) was clicked on. + int hit_node = draw_check_rr_node_hit(x, y); - return highlight_rr_nodes(hit_node); + return highlight_rr_nodes(hit_node); } # if defined(X11) && !defined(__MINGW32__) @@ -2903,209 +2849,206 @@ void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* std::string key(key_name); } # else -void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, - char* /*key_name*/) { +void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* /*key_name*/) { } # endif -void act_on_mouse_press(ezgl::application *app, GdkEventButton *event, double x, - double y) { - // std::cout << "User clicked the "; - - if (event->button == 1) { - // std::cout << "left "; - - if (window_mode) { - //click on any two points to form new window rectangle bound - - if (!window_point_1_collected) { - //collect first point data - - window_point_1_collected = true; - point_1 = { x, y }; - } else { - //collect second point data - - //click on any two points to form new window rectangle bound - ezgl::point2d point_2 = { x, y }; - ezgl::rectangle current_window = (app->get_canvas( - app->get_main_canvas_id()))->get_camera().get_world(); - - //calculate a rectangle with the same ratio based on the two clicks - double window_ratio = current_window.height() - / current_window.width(); - double new_height = abs(point_1.y - point_2.y); - double new_width = new_height / window_ratio; - - //zoom in - ezgl::rectangle new_window = { point_1, { point_1.x + new_width, - point_2.y } }; - (app->get_canvas(app->get_main_canvas_id()))->get_camera().set_world( - new_window); - - //reset flags - window_mode = false; - window_point_1_collected = false; - } - app->refresh_drawing(); - } else { - // regular clicking mode - - /* This routine is called when the user clicks in the graphics area. * - * It determines if a clb was clicked on. If one was, it is * - * highlighted in green, it's fanin nets and clbs are highlighted in * - * blue and it's fanout is highlighted in red. If no clb was * - * clicked on (user clicked on white space) any old highlighting is * - * removed. Note that even though global nets are not drawn, their * - * fanins and fanouts are highlighted when you click on a block * - * attached to them. */ - - /* Control + mouse click to select multiple nets. */ - if (!(event->state & GDK_CONTROL_MASK)) - deselect_all(); - - //Check if we hit an rr node - // Note that we check this before checking for a block, since pins and routing may appear overtop of a multi-width/height block - if (highlight_rr_nodes(x, y)) { - return; //Selected an rr node - } - - highlight_blocks(x, y); - } - } - // else if (event->button == 2) - // std::cout << "middle "; - // else if (event->button == 3) - // std::cout << "right "; - - // std::cout << "mouse button at coordinates (" << x << "," << y << ") " << std::endl; +void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, double y) { + // std::cout << "User clicked the "; + + if (event->button == 1) { + // std::cout << "left "; + + if (window_mode) { + //click on any two points to form new window rectangle bound + + if (!window_point_1_collected) { + //collect first point data + + window_point_1_collected = true; + point_1 = {x, y}; + } else { + //collect second point data + + //click on any two points to form new window rectangle bound + ezgl::point2d point_2 = {x, y}; + ezgl::rectangle current_window = (app->get_canvas( + app->get_main_canvas_id())) + ->get_camera() + .get_world(); + + //calculate a rectangle with the same ratio based on the two clicks + double window_ratio = current_window.height() + / current_window.width(); + double new_height = abs(point_1.y - point_2.y); + double new_width = new_height / window_ratio; + + //zoom in + ezgl::rectangle new_window = {point_1, {point_1.x + new_width, point_2.y}}; + (app->get_canvas(app->get_main_canvas_id()))->get_camera().set_world(new_window); + + //reset flags + window_mode = false; + window_point_1_collected = false; + } + app->refresh_drawing(); + } else { + // regular clicking mode + + /* This routine is called when the user clicks in the graphics area. * + * It determines if a clb was clicked on. If one was, it is * + * highlighted in green, it's fanin nets and clbs are highlighted in * + * blue and it's fanout is highlighted in red. If no clb was * + * clicked on (user clicked on white space) any old highlighting is * + * removed. Note that even though global nets are not drawn, their * + * fanins and fanouts are highlighted when you click on a block * + * attached to them. */ + + /* Control + mouse click to select multiple nets. */ + if (!(event->state & GDK_CONTROL_MASK)) + deselect_all(); + + //Check if we hit an rr node + // Note that we check this before checking for a block, since pins and routing may appear overtop of a multi-width/height block + if (highlight_rr_nodes(x, y)) { + return; //Selected an rr node + } + + highlight_blocks(x, y); + } + } + // else if (event->button == 2) + // std::cout << "middle "; + // else if (event->button == 3) + // std::cout << "right "; + + // std::cout << "mouse button at coordinates (" << x << "," << y << ") " << std::endl; } -void act_on_mouse_move(ezgl::application *app, GdkEventButton *event, double x, - double y) { - // std::cout << "Mouse move at coordinates (" << x << "," << y << ") "<< std::endl; - - // user has clicked the window button, in window mode - if (window_point_1_collected) { - // draw a grey, dashed-line box to indicate the zoom-in region - app->refresh_drawing(); - ezgl::renderer *g = app->get_renderer(); - g->set_line_dash(ezgl::line_dash::asymmetric_5_3); - g->set_color(blk_GREY); - g->set_line_width(2); - g->draw_rectangle(point_1, { x, y }); - return; - } - - // user has not clicked the window button, in regular mode - t_draw_state *draw_state = get_draw_state_vars(); - - if (draw_state->draw_rr_toggle != DRAW_NO_RR) { - int hit_node = draw_check_rr_node_hit(x, y); - - if (hit_node != OPEN) { - //Update message - - std::string info = describe_rr_node(hit_node); - std::string msg = vtr::string_fmt("Moused over %s", info.c_str()); - app->update_message(msg.c_str()); - } else { - if (!rr_highlight_message.empty()) { - app->update_message(rr_highlight_message.c_str()); - } else { - app->update_message(draw_state->default_message); - } - } - } - event = event; // just for hiding warning message +void act_on_mouse_move(ezgl::application* app, GdkEventButton* event, double x, double y) { + // std::cout << "Mouse move at coordinates (" << x << "," << y << ") "<< std::endl; + + // user has clicked the window button, in window mode + if (window_point_1_collected) { + // draw a grey, dashed-line box to indicate the zoom-in region + app->refresh_drawing(); + ezgl::renderer* g = app->get_renderer(); + g->set_line_dash(ezgl::line_dash::asymmetric_5_3); + g->set_color(blk_GREY); + g->set_line_width(2); + g->draw_rectangle(point_1, {x, y}); + return; + } + + // user has not clicked the window button, in regular mode + t_draw_state* draw_state = get_draw_state_vars(); + + if (draw_state->draw_rr_toggle != DRAW_NO_RR) { + int hit_node = draw_check_rr_node_hit(x, y); + + if (hit_node != OPEN) { + //Update message + + std::string info = describe_rr_node(hit_node); + std::string msg = vtr::string_fmt("Moused over %s", info.c_str()); + app->update_message(msg.c_str()); + } else { + if (!rr_highlight_message.empty()) { + app->update_message(rr_highlight_message.c_str()); + } else { + app->update_message(draw_state->default_message); + } + } + } + event = event; // just for hiding warning message } void draw_highlight_blocks_color(t_logical_block_type_ptr type, - ClusterBlockId blk_id) { - int k, iclass; - ClusterBlockId fanblk; - - t_draw_state *draw_state = get_draw_state_vars(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - - for (k = 0; k < type->pb_type->num_pins; k++) { /* Each pin on a CLB */ - ClusterNetId net_id = cluster_ctx.clb_nlist.block_net(blk_id, k); - - if (net_id == ClusterNetId::INVALID()) - continue; - - auto physical_tile = physical_tile_type(blk_id); - int physical_pin = get_physical_pin(physical_tile, type, k); - - iclass = physical_tile->pin_class[physical_pin]; - - if (physical_tile->class_inf[iclass].type == DRIVER) { /* Fanout */ - if (draw_state->block_color(blk_id) == SELECTED_COLOR) { - /* If block already highlighted, de-highlight the fanout. (the deselect case)*/ - draw_state->net_color[net_id] = ezgl::BLACK; - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); - draw_reset_blk_color(fanblk); - } - } else { - /* Highlight the fanout */ - draw_state->net_color[net_id] = DRIVES_IT_COLOR; - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); - draw_state->set_block_color(fanblk, DRIVES_IT_COLOR); - } - } - } else { /* This net is fanin to the block. */ - if (draw_state->block_color(blk_id) == SELECTED_COLOR) { - /* If block already highlighted, de-highlight the fanin. (the deselect case)*/ - draw_state->net_color[net_id] = ezgl::BLACK; - fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ - draw_reset_blk_color(fanblk); - } else { - /* Highlight the fanin */ - draw_state->net_color[net_id] = DRIVEN_BY_IT_COLOR; - fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ - draw_state->set_block_color(fanblk, DRIVEN_BY_IT_COLOR); - } - } - } - - if (draw_state->block_color(blk_id) == SELECTED_COLOR) { - /* If block already highlighted, de-highlight the selected block. */ - draw_reset_blk_color(blk_id); - } else { - /* Highlight the selected block. */ - draw_state->set_block_color(blk_id, SELECTED_COLOR); - } + ClusterBlockId blk_id) { + int k, iclass; + ClusterBlockId fanblk; + + t_draw_state* draw_state = get_draw_state_vars(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + + for (k = 0; k < type->pb_type->num_pins; k++) { /* Each pin on a CLB */ + ClusterNetId net_id = cluster_ctx.clb_nlist.block_net(blk_id, k); + + if (net_id == ClusterNetId::INVALID()) + continue; + + auto physical_tile = physical_tile_type(blk_id); + int physical_pin = get_physical_pin(physical_tile, type, k); + + iclass = physical_tile->pin_class[physical_pin]; + + if (physical_tile->class_inf[iclass].type == DRIVER) { /* Fanout */ + if (draw_state->block_color(blk_id) == SELECTED_COLOR) { + /* If block already highlighted, de-highlight the fanout. (the deselect case)*/ + draw_state->net_color[net_id] = ezgl::BLACK; + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); + draw_reset_blk_color(fanblk); + } + } else { + /* Highlight the fanout */ + draw_state->net_color[net_id] = DRIVES_IT_COLOR; + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + fanblk = cluster_ctx.clb_nlist.pin_block(pin_id); + draw_state->set_block_color(fanblk, DRIVES_IT_COLOR); + } + } + } else { /* This net is fanin to the block. */ + if (draw_state->block_color(blk_id) == SELECTED_COLOR) { + /* If block already highlighted, de-highlight the fanin. (the deselect case)*/ + draw_state->net_color[net_id] = ezgl::BLACK; + fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ + draw_reset_blk_color(fanblk); + } else { + /* Highlight the fanin */ + draw_state->net_color[net_id] = DRIVEN_BY_IT_COLOR; + fanblk = cluster_ctx.clb_nlist.net_driver_block(net_id); /* DRIVER to net */ + draw_state->set_block_color(fanblk, DRIVEN_BY_IT_COLOR); + } + } + } + + if (draw_state->block_color(blk_id) == SELECTED_COLOR) { + /* If block already highlighted, de-highlight the selected block. */ + draw_reset_blk_color(blk_id); + } else { + /* Highlight the selected block. */ + draw_state->set_block_color(blk_id, SELECTED_COLOR); + } } void deselect_all() { - // Sets the color of all clbs, nets and rr_nodes to the default. - // as well as clearing the highlighed sub-block - - t_draw_state *draw_state = get_draw_state_vars(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &device_ctx = g_vpr_ctx.device(); - - /* Create some colour highlighting */ - for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { - if (blk_id != ClusterBlockId::INVALID()) - draw_reset_blk_color(blk_id); - } - - for (auto net_id : cluster_ctx.clb_nlist.nets()) - draw_state->net_color[net_id] = ezgl::BLACK; - - for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { - draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; - draw_state->draw_rr_node[i].node_highlighted = false; - } - get_selected_sub_block_info().clear(); + // Sets the color of all clbs, nets and rr_nodes to the default. + // as well as clearing the highlighed sub-block + + t_draw_state* draw_state = get_draw_state_vars(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& device_ctx = g_vpr_ctx.device(); + + /* Create some colour highlighting */ + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + if (blk_id != ClusterBlockId::INVALID()) + draw_reset_blk_color(blk_id); + } + + for (auto net_id : cluster_ctx.clb_nlist.nets()) + draw_state->net_color[net_id] = ezgl::BLACK; + + for (size_t i = 0; i < device_ctx.rr_nodes.size(); i++) { + draw_state->draw_rr_node[i].color = DEFAULT_RR_NODE_COLOR; + draw_state->draw_rr_node[i].node_highlighted = false; + } + get_selected_sub_block_info().clear(); } static void draw_reset_blk_color(ClusterBlockId blk_id) { - t_draw_state *draw_state = get_draw_state_vars(); - draw_state->reset_block_color(blk_id); + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->reset_block_color(blk_id); } /** @@ -3117,27 +3060,25 @@ static void draw_reset_blk_color(ClusterBlockId blk_id) { * A 'relative_position' of 1. draws the triangle centered at 'end'. * Fractional values draw the triangle along the line */ -void draw_triangle_along_line(ezgl::renderer *g, ezgl::point2d start, - ezgl::point2d end, float relative_position, float arrow_size) { - VTR_ASSERT(relative_position >= 0. && relative_position <= 1.); - float xdelta = end.x - start.x; - float ydelta = end.y - start.y; +void draw_triangle_along_line(ezgl::renderer* g, ezgl::point2d start, ezgl::point2d end, float relative_position, float arrow_size) { + VTR_ASSERT(relative_position >= 0. && relative_position <= 1.); + float xdelta = end.x - start.x; + float ydelta = end.y - start.y; - float xtri = start.x + xdelta * relative_position; - float ytri = start.y + ydelta * relative_position; + float xtri = start.x + xdelta * relative_position; + float ytri = start.y + ydelta * relative_position; - draw_triangle_along_line(g, xtri, ytri, start.x, end.x, start.y, end.y, - arrow_size); + draw_triangle_along_line(g, xtri, ytri, start.x, end.x, start.y, end.y, + arrow_size); } /* Draws a triangle with it's center at loc, and of length & width * arrow_size, rotated such that it points in the direction * of the directed line segment start -> end. */ -void draw_triangle_along_line(ezgl::renderer *g, ezgl::point2d loc, - ezgl::point2d start, ezgl::point2d end, float arrow_size) { - draw_triangle_along_line(g, loc.x, loc.y, start.x, end.x, start.y, end.y, - arrow_size); +void draw_triangle_along_line(ezgl::renderer* g, ezgl::point2d loc, ezgl::point2d start, ezgl::point2d end, float arrow_size) { + draw_triangle_along_line(g, loc.x, loc.y, start.x, end.x, start.y, end.y, + arrow_size); } /** @@ -3148,35 +3089,33 @@ void draw_triangle_along_line(ezgl::renderer *g, ezgl::point2d loc, * Note that the parameters are in a strange order */ -void draw_triangle_along_line(ezgl::renderer *g, float xend, float yend, - float x1, float x2, float y1, float y2, float arrow_size) { - float switch_rad = arrow_size / 2; - float xdelta, ydelta; - float magnitude; - float xunit, yunit; - float xbaseline, ybaseline; +void draw_triangle_along_line(ezgl::renderer* g, float xend, float yend, float x1, float x2, float y1, float y2, float arrow_size) { + float switch_rad = arrow_size / 2; + float xdelta, ydelta; + float magnitude; + float xunit, yunit; + float xbaseline, ybaseline; - std::vector poly; + std::vector poly; - xdelta = x2 - x1; - ydelta = y2 - y1; - magnitude = sqrt(xdelta * xdelta + ydelta * ydelta); + xdelta = x2 - x1; + ydelta = y2 - y1; + magnitude = sqrt(xdelta * xdelta + ydelta * ydelta); - xunit = xdelta / magnitude; - yunit = ydelta / magnitude; + xunit = xdelta / magnitude; + yunit = ydelta / magnitude; - poly.push_back( { xend + xunit * switch_rad, yend + yunit * switch_rad }); - xbaseline = xend - xunit * switch_rad; - ybaseline = yend - yunit * switch_rad; - poly.push_back( - { xbaseline + yunit * switch_rad, ybaseline - xunit * switch_rad }); - poly.push_back( - { xbaseline - yunit * switch_rad, ybaseline + xunit * switch_rad }); + poly.push_back({xend + xunit * switch_rad, yend + yunit * switch_rad}); + xbaseline = xend - xunit * switch_rad; + ybaseline = yend - yunit * switch_rad; + poly.push_back( + {xbaseline + yunit * switch_rad, ybaseline - xunit * switch_rad}); + poly.push_back( + {xbaseline - yunit * switch_rad, ybaseline + xunit * switch_rad}); - g->fill_poly(poly); + g->fill_poly(poly); } - static void draw_pin_to_chan_edge(int pin_node, int 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 * @@ -3383,847 +3322,847 @@ static void draw_pin_to_pin(int opin_node, int ipin_node, ezgl::renderer* g) { draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); } -static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer *g) { - auto &device_ctx = g_vpr_ctx.device(); +static void draw_pin_to_sink(int ipin_node, int sink_node, ezgl::renderer* g) { + auto& device_ctx = g_vpr_ctx.device(); - float x1 = 0, y1 = 0; - /* Draw the line for each ipin on different sides */ - for (const e_side &pin_side : SIDES) { - if (!device_ctx.rr_nodes[ipin_node].is_node_on_specific_side( - pin_side)) { - continue; - } + float x1 = 0, y1 = 0; + /* Draw the line for each ipin on different sides */ + for (const e_side& pin_side : SIDES) { + if (!device_ctx.rr_nodes[ipin_node].is_node_on_specific_side( + pin_side)) { + continue; + } - draw_get_rr_pin_coords(ipin_node, &x1, &y1, pin_side); + draw_get_rr_pin_coords(ipin_node, &x1, &y1, pin_side); - float x2 = 0, y2 = 0; - draw_get_rr_src_sink_coords(device_ctx.rr_nodes[sink_node], &x2, &y2); + float x2 = 0, y2 = 0; + draw_get_rr_src_sink_coords(device_ctx.rr_nodes[sink_node], &x2, &y2); - g->draw_line( { x1, y1 }, { x2, y2 }); + g->draw_line({x1, y1}, {x2, y2}); - float xend = x2 + (x1 - x2) / 10.; - float yend = y2 + (y1 - y2) / 10.; - draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); - } + float xend = x2 + (x1 - x2) / 10.; + float yend = y2 + (y1 - y2) / 10.; + draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); + } } -static void draw_source_to_pin(int source_node, int opin_node, - ezgl::renderer *g) { - auto &device_ctx = g_vpr_ctx.device(); +static void draw_source_to_pin(int source_node, int opin_node, ezgl::renderer* g) { + auto& device_ctx = g_vpr_ctx.device(); - float x1 = 0, y1 = 0; - draw_get_rr_src_sink_coords(device_ctx.rr_nodes[source_node], &x1, &y1); + float x1 = 0, y1 = 0; + draw_get_rr_src_sink_coords(device_ctx.rr_nodes[source_node], &x1, &y1); - /* Draw the line for each ipin on different sides */ - for (const e_side &pin_side : SIDES) { - if (!device_ctx.rr_nodes[opin_node].is_node_on_specific_side( - pin_side)) { - continue; - } + /* Draw the line for each ipin on different sides */ + for (const e_side& pin_side : SIDES) { + if (!device_ctx.rr_nodes[opin_node].is_node_on_specific_side( + pin_side)) { + continue; + } - float x2 = 0, y2 = 0; - draw_get_rr_pin_coords(opin_node, &x2, &y2, pin_side); + float x2 = 0, y2 = 0; + draw_get_rr_pin_coords(opin_node, &x2, &y2, pin_side); - g->draw_line( { x1, y1 }, { x2, y2 }); + g->draw_line({x1, y1}, {x2, y2}); - float xend = x2 + (x1 - x2) / 10.; - float yend = y2 + (y1 - y2) / 10.; - draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); - } + float xend = x2 + (x1 - x2) / 10.; + float yend = y2 + (y1 - y2) / 10.; + draw_triangle_along_line(g, xend, yend, x1, x2, y1, y2); + } } -static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, - float height, int size, ezgl::renderer *g) { - g->set_color(ezgl::YELLOW); - auto bounds = draw_mux(origin, orientation, height, g); +static inline void draw_mux_with_size(ezgl::point2d origin, e_side orientation, float height, int size, ezgl::renderer* g) { + g->set_color(ezgl::YELLOW); + auto bounds = draw_mux(origin, orientation, height, g); - g->set_color(ezgl::BLACK); - g->draw_text(bounds.center(), std::to_string(size), bounds.width(), - bounds.height()); + g->set_color(ezgl::BLACK); + g->draw_text(bounds.center(), std::to_string(size), bounds.width(), + bounds.height()); } //Draws a mux -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, - float height, ezgl::renderer *g) { - return draw_mux(origin, orientation, height, 0.4 * height, 0.6, g); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, ezgl::renderer* g) { + return draw_mux(origin, orientation, height, 0.4 * height, 0.6, g); } //Draws a mux, height/width define the bounding box, scale [0.,1.] controls the slope of the muxes sides -static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, - float height, float width, float scale, ezgl::renderer *g) { - std::vector mux_polygon; - - switch (orientation) { - case TOP: - //Clock-wise from bottom left - mux_polygon.push_back( { origin.x - height / 2, origin.y - width / 2 }); - mux_polygon.push_back( - { origin.x - (scale * height) / 2, origin.y + width / 2 }); - mux_polygon.push_back( - { origin.x + (scale * height) / 2, origin.y + width / 2 }); - mux_polygon.push_back( { origin.x + height / 2, origin.y - width / 2 }); - break; - case BOTTOM: - //Clock-wise from bottom left - mux_polygon.push_back( - { origin.x - (scale * height) / 2, origin.y - width / 2 }); - mux_polygon.push_back( { origin.x - height / 2, origin.y + width / 2 }); - mux_polygon.push_back( { origin.x + height / 2, origin.y + width / 2 }); - mux_polygon.push_back( - { origin.x + (scale * height) / 2, origin.y - width / 2 }); - break; - case LEFT: - //Clock-wise from bottom left - mux_polygon.push_back( - { origin.x - width / 2, origin.y - (scale * height) / 2 }); - mux_polygon.push_back( - { origin.x - width / 2, origin.y + (scale * height) / 2 }); - mux_polygon.push_back( { origin.x + width / 2, origin.y + height / 2 }); - mux_polygon.push_back( { origin.x + width / 2, origin.y - height / 2 }); - break; - case RIGHT: - //Clock-wise from bottom left - mux_polygon.push_back( { origin.x - width / 2, origin.y - height / 2 }); - mux_polygon.push_back( { origin.x - width / 2, origin.y + height / 2 }); - mux_polygon.push_back( - { origin.x + width / 2, origin.y + (scale * height) / 2 }); - mux_polygon.push_back( - { origin.x + width / 2, origin.y - (scale * height) / 2 }); - break; - - default: - VTR_ASSERT_MSG(false, "Unrecognized orientation"); - } - g->fill_poly(mux_polygon); - - ezgl::point2d min((float) mux_polygon[0].x, (float) mux_polygon[0].y); - ezgl::point2d max((float) mux_polygon[0].x, (float) mux_polygon[0].y); - for (const auto &point : mux_polygon) { - min.x = std::min((float) min.x, (float) point.x); - min.y = std::min((float) min.y, (float) point.y); - max.x = std::max((float) max.x, (float) point.x); - max.y = std::max((float) max.y, (float) point.y); - } - - return ezgl::rectangle(min, max); +static inline ezgl::rectangle draw_mux(ezgl::point2d origin, e_side orientation, float height, float width, float scale, ezgl::renderer* g) { + std::vector mux_polygon; + + switch (orientation) { + case TOP: + //Clock-wise from bottom left + mux_polygon.push_back({origin.x - height / 2, origin.y - width / 2}); + mux_polygon.push_back( + {origin.x - (scale * height) / 2, origin.y + width / 2}); + mux_polygon.push_back( + {origin.x + (scale * height) / 2, origin.y + width / 2}); + mux_polygon.push_back({origin.x + height / 2, origin.y - width / 2}); + break; + case BOTTOM: + //Clock-wise from bottom left + mux_polygon.push_back( + {origin.x - (scale * height) / 2, origin.y - width / 2}); + mux_polygon.push_back({origin.x - height / 2, origin.y + width / 2}); + mux_polygon.push_back({origin.x + height / 2, origin.y + width / 2}); + mux_polygon.push_back( + {origin.x + (scale * height) / 2, origin.y - width / 2}); + break; + case LEFT: + //Clock-wise from bottom left + mux_polygon.push_back( + {origin.x - width / 2, origin.y - (scale * height) / 2}); + mux_polygon.push_back( + {origin.x - width / 2, origin.y + (scale * height) / 2}); + mux_polygon.push_back({origin.x + width / 2, origin.y + height / 2}); + mux_polygon.push_back({origin.x + width / 2, origin.y - height / 2}); + break; + case RIGHT: + //Clock-wise from bottom left + mux_polygon.push_back({origin.x - width / 2, origin.y - height / 2}); + mux_polygon.push_back({origin.x - width / 2, origin.y + height / 2}); + mux_polygon.push_back( + {origin.x + width / 2, origin.y + (scale * height) / 2}); + mux_polygon.push_back( + {origin.x + width / 2, origin.y - (scale * height) / 2}); + break; + + default: + VTR_ASSERT_MSG(false, "Unrecognized orientation"); + } + g->fill_poly(mux_polygon); + + ezgl::point2d min((float)mux_polygon[0].x, (float)mux_polygon[0].y); + ezgl::point2d max((float)mux_polygon[0].x, (float)mux_polygon[0].y); + for (const auto& point : mux_polygon) { + min.x = std::min((float)min.x, (float)point.x); + min.y = std::min((float)min.y, (float)point.y); + max.x = std::max((float)max.x, (float)point.x); + max.y = std::max((float)max.y, (float)point.y); + } + + return ezgl::rectangle(min, max); } ezgl::point2d tnode_draw_coord(tatum::NodeId node) { - auto &atom_ctx = g_vpr_ctx.atom(); + auto& atom_ctx = g_vpr_ctx.atom(); - AtomPinId pin = atom_ctx.lookup.tnode_atom_pin(node); - return atom_pin_draw_coord(pin); + AtomPinId pin = atom_ctx.lookup.tnode_atom_pin(node); + return atom_pin_draw_coord(pin); } ezgl::point2d atom_pin_draw_coord(AtomPinId pin) { - auto &atom_ctx = g_vpr_ctx.atom(); + auto& atom_ctx = g_vpr_ctx.atom(); - AtomBlockId blk = atom_ctx.nlist.pin_block(pin); - ClusterBlockId clb_index = atom_ctx.lookup.atom_clb(blk); - const t_pb_graph_node *pg_gnode = atom_ctx.lookup.atom_pb_graph_node(blk); + AtomBlockId blk = atom_ctx.nlist.pin_block(pin); + ClusterBlockId clb_index = atom_ctx.lookup.atom_clb(blk); + const t_pb_graph_node* pg_gnode = atom_ctx.lookup.atom_pb_graph_node(blk); - t_draw_coords *draw_coords = get_draw_coords_vars(); - ezgl::rectangle pb_bbox = draw_coords->get_absolute_pb_bbox(clb_index, - pg_gnode); + t_draw_coords* draw_coords = get_draw_coords_vars(); + ezgl::rectangle pb_bbox = draw_coords->get_absolute_pb_bbox(clb_index, + pg_gnode); - //We place each atom pin inside it's pb bounding box - //and distribute the pins along it's vertical centre line - const float FRACTION_USABLE_WIDTH = 0.8; - float width = pb_bbox.width(); - float usable_width = width * FRACTION_USABLE_WIDTH; - float x_offset = pb_bbox.left() + width * (1 - FRACTION_USABLE_WIDTH) / 2; + //We place each atom pin inside it's pb bounding box + //and distribute the pins along it's vertical centre line + const float FRACTION_USABLE_WIDTH = 0.8; + float width = pb_bbox.width(); + float usable_width = width * FRACTION_USABLE_WIDTH; + float x_offset = pb_bbox.left() + width * (1 - FRACTION_USABLE_WIDTH) / 2; - int pin_index, pin_total; - find_pin_index_at_model_scope(pin, blk, &pin_index, &pin_total); + int pin_index, pin_total; + find_pin_index_at_model_scope(pin, blk, &pin_index, &pin_total); - const ezgl::point2d point = - { x_offset + usable_width * pin_index / ((float) pin_total), - pb_bbox.center_y() }; + const ezgl::point2d point = {x_offset + usable_width * pin_index / ((float)pin_total), + pb_bbox.center_y()}; - return point; + return point; } -static void draw_crit_path(ezgl::renderer *g) { - tatum::TimingPathCollector path_collector; - - t_draw_state *draw_state = get_draw_state_vars(); - auto &timing_ctx = g_vpr_ctx.timing(); - - if (draw_state->show_crit_path == DRAW_NO_CRIT_PATH) { - return; - } - - if (!draw_state->setup_timing_info) { - return; //No timing to draw - } - - //Get the worst timing path - auto paths = path_collector.collect_worst_setup_timing_paths( - *timing_ctx.graph, - *(draw_state->setup_timing_info->setup_analyzer()), 1); - tatum::TimingPath path = paths[0]; - - //Walk through the timing path drawing each edge - tatum::NodeId prev_node; - float prev_arr_time = std::numeric_limits::quiet_NaN(); - int i = 0; - for (tatum::TimingPathElem elem : path.data_arrival_path().elements()) { - tatum::NodeId node = elem.node(); - float arr_time = elem.tag().time(); - if (prev_node) { - //We draw each 'edge' in a different color, this allows users to identify the stages and - //any routing which corresponds to the edge - // - //We pick colors from the kelly max-contrast list, for long paths there may be repeats - ezgl::color color = kelly_max_contrast_colors[i++ - % kelly_max_contrast_colors.size()]; - - float delay = arr_time - prev_arr_time; - if (draw_state->show_crit_path == DRAW_CRIT_PATH_FLYLINES - || draw_state->show_crit_path - == DRAW_CRIT_PATH_FLYLINES_DELAYS) { - g->set_color(color); - g->set_line_dash(ezgl::line_dash::none); - g->set_line_width(4); - draw_flyline_timing_edge(tnode_draw_coord(prev_node), - tnode_draw_coord(node), delay, g); - } else { - VTR_ASSERT(draw_state->show_crit_path != DRAW_NO_CRIT_PATH); - - //Draw the routed version of the timing edge - draw_routed_timing_edge(prev_node, node, delay, color, g); - } - } - prev_node = node; - prev_arr_time = arr_time; - } +static void draw_crit_path(ezgl::renderer* g) { + tatum::TimingPathCollector path_collector; + + t_draw_state* draw_state = get_draw_state_vars(); + auto& timing_ctx = g_vpr_ctx.timing(); + + if (draw_state->show_crit_path == DRAW_NO_CRIT_PATH) { + return; + } + + if (!draw_state->setup_timing_info) { + return; //No timing to draw + } + + //Get the worst timing path + auto paths = path_collector.collect_worst_setup_timing_paths( + *timing_ctx.graph, + *(draw_state->setup_timing_info->setup_analyzer()), 1); + tatum::TimingPath path = paths[0]; + + //Walk through the timing path drawing each edge + tatum::NodeId prev_node; + float prev_arr_time = std::numeric_limits::quiet_NaN(); + int i = 0; + for (tatum::TimingPathElem elem : path.data_arrival_path().elements()) { + tatum::NodeId node = elem.node(); + float arr_time = elem.tag().time(); + if (prev_node) { + //We draw each 'edge' in a different color, this allows users to identify the stages and + //any routing which corresponds to the edge + // + //We pick colors from the kelly max-contrast list, for long paths there may be repeats + ezgl::color color = kelly_max_contrast_colors[i++ + % kelly_max_contrast_colors.size()]; + + float delay = arr_time - prev_arr_time; + if (draw_state->show_crit_path == DRAW_CRIT_PATH_FLYLINES + || draw_state->show_crit_path + == DRAW_CRIT_PATH_FLYLINES_DELAYS) { + g->set_color(color); + g->set_line_dash(ezgl::line_dash::none); + g->set_line_width(4); + draw_flyline_timing_edge(tnode_draw_coord(prev_node), + tnode_draw_coord(node), delay, g); + } else { + VTR_ASSERT(draw_state->show_crit_path != DRAW_NO_CRIT_PATH); + + //Draw the routed version of the timing edge + draw_routed_timing_edge(prev_node, node, delay, color, g); + } + } + prev_node = node; + prev_arr_time = arr_time; + } } -static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, - float incr_delay, ezgl::renderer *g) { - g->draw_line(start, end); - draw_triangle_along_line(g, start, end, 0.95, 40 * DEFAULT_ARROW_SIZE); - draw_triangle_along_line(g, start, end, 0.05, 40 * DEFAULT_ARROW_SIZE); - - bool draw_delays = (get_draw_state_vars()->show_crit_path - == DRAW_CRIT_PATH_FLYLINES_DELAYS - || get_draw_state_vars()->show_crit_path - == DRAW_CRIT_PATH_ROUTING_DELAYS); - if (draw_delays) { - //Determine the strict bounding box based on the lines start/end - float min_x = std::min(start.x, end.x); - float max_x = std::max(start.x, end.x); - float min_y = std::min(start.y, end.y); - float max_y = std::max(start.y, end.y); - - //If we have a nearly horizontal/vertical line the bbox is too - //small to draw the text, so widen it by a tile (i.e. CLB) width - float tile_width = get_draw_coords_vars()->get_tile_width(); - if (max_x - min_x < tile_width) { - max_x += tile_width / 2; - min_x -= tile_width / 2; - } - if (max_y - min_y < tile_width) { - max_y += tile_width / 2; - min_y -= tile_width / 2; - } - - //TODO: draw the delays nicer - // * rotate to match edge - // * offset from line - // * track visible in window - ezgl::rectangle text_bbox( { min_x, min_y }, { max_x, max_y }); - - std::stringstream ss; - ss.precision(3); - ss << 1e9 * incr_delay; //In nanoseconds - std::string incr_delay_str = ss.str(); - - // Get the angle of line, to rotate the text - float text_angle = (180 / M_PI) - * atan((end.y - start.y) / (end.x - start.x)); - - // Get the screen coordinates for text drawing - ezgl::rectangle screen_coords = g->world_to_screen(text_bbox); - g->set_text_rotation(text_angle); - - // Set the text colour to black to differentiate it from the line - g->set_font_size(16); - g->set_color(ezgl::color(0, 0, 0)); - - g->set_coordinate_system(ezgl::SCREEN); - - // Find an offset so it is sitting on top/below of the line - float x_offset = screen_coords.center().x - - 8 * sin(text_angle * (M_PI / 180)); - float y_offset = screen_coords.center().y - - 8 * cos(text_angle * (M_PI / 180)); - - ezgl::point2d offset_text_bbox(x_offset, y_offset); - g->draw_text(offset_text_bbox, incr_delay_str.c_str(), - text_bbox.width(), text_bbox.height()); - - g->set_font_size(14); - - g->set_text_rotation(0); - g->set_coordinate_system(ezgl::WORLD); - } +static void draw_flyline_timing_edge(ezgl::point2d start, ezgl::point2d end, float incr_delay, ezgl::renderer* g) { + g->draw_line(start, end); + draw_triangle_along_line(g, start, end, 0.95, 40 * DEFAULT_ARROW_SIZE); + draw_triangle_along_line(g, start, end, 0.05, 40 * DEFAULT_ARROW_SIZE); + + bool draw_delays = (get_draw_state_vars()->show_crit_path + == DRAW_CRIT_PATH_FLYLINES_DELAYS + || get_draw_state_vars()->show_crit_path + == DRAW_CRIT_PATH_ROUTING_DELAYS); + if (draw_delays) { + //Determine the strict bounding box based on the lines start/end + float min_x = std::min(start.x, end.x); + float max_x = std::max(start.x, end.x); + float min_y = std::min(start.y, end.y); + float max_y = std::max(start.y, end.y); + + //If we have a nearly horizontal/vertical line the bbox is too + //small to draw the text, so widen it by a tile (i.e. CLB) width + float tile_width = get_draw_coords_vars()->get_tile_width(); + if (max_x - min_x < tile_width) { + max_x += tile_width / 2; + min_x -= tile_width / 2; + } + if (max_y - min_y < tile_width) { + max_y += tile_width / 2; + min_y -= tile_width / 2; + } + + //TODO: draw the delays nicer + // * rotate to match edge + // * offset from line + // * track visible in window + ezgl::rectangle text_bbox({min_x, min_y}, {max_x, max_y}); + + std::stringstream ss; + ss.precision(3); + ss << 1e9 * incr_delay; //In nanoseconds + std::string incr_delay_str = ss.str(); + + // Get the angle of line, to rotate the text + float text_angle = (180 / M_PI) + * atan((end.y - start.y) / (end.x - start.x)); + + // Get the screen coordinates for text drawing + ezgl::rectangle screen_coords = g->world_to_screen(text_bbox); + g->set_text_rotation(text_angle); + + // Set the text colour to black to differentiate it from the line + g->set_font_size(16); + g->set_color(ezgl::color(0, 0, 0)); + + g->set_coordinate_system(ezgl::SCREEN); + + // Find an offset so it is sitting on top/below of the line + float x_offset = screen_coords.center().x + - 8 * sin(text_angle * (M_PI / 180)); + float y_offset = screen_coords.center().y + - 8 * cos(text_angle * (M_PI / 180)); + + ezgl::point2d offset_text_bbox(x_offset, y_offset); + g->draw_text(offset_text_bbox, incr_delay_str.c_str(), + text_bbox.width(), text_bbox.height()); + + g->set_font_size(14); + + g->set_text_rotation(0); + g->set_coordinate_system(ezgl::WORLD); + } } static void draw_routed_timing_edge(tatum::NodeId start_tnode, - tatum::NodeId end_tnode, float incr_delay, ezgl::color color, - ezgl::renderer *g) { - draw_routed_timing_edge_connection(start_tnode, end_tnode, color, g); - - g->set_line_dash(ezgl::line_dash::asymmetric_5_3); - g->set_line_width(3); - g->set_color(color); + tatum::NodeId end_tnode, + float incr_delay, + ezgl::color color, + ezgl::renderer* g) { + draw_routed_timing_edge_connection(start_tnode, end_tnode, color, g); + + g->set_line_dash(ezgl::line_dash::asymmetric_5_3); + g->set_line_width(3); + g->set_color(color); - draw_flyline_timing_edge((ezgl::point2d) tnode_draw_coord(start_tnode), - (ezgl::point2d) tnode_draw_coord(end_tnode), (float) incr_delay, - (ezgl::renderer*) g); + draw_flyline_timing_edge((ezgl::point2d)tnode_draw_coord(start_tnode), + (ezgl::point2d)tnode_draw_coord(end_tnode), (float)incr_delay, + (ezgl::renderer*)g); - g->set_line_width(0); - g->set_line_dash(ezgl::line_dash::none); + g->set_line_width(0); + g->set_line_dash(ezgl::line_dash::none); } //Collect all the drawing locations associated with the timing edge between start and end static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, - tatum::NodeId sink_tnode, ezgl::color color, ezgl::renderer *g) { - auto &atom_ctx = g_vpr_ctx.atom(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &timing_ctx = g_vpr_ctx.timing(); - - AtomPinId atom_src_pin = atom_ctx.lookup.tnode_atom_pin(src_tnode); - AtomPinId atom_sink_pin = atom_ctx.lookup.tnode_atom_pin(sink_tnode); - - std::vector points; - points.push_back(atom_pin_draw_coord(atom_src_pin)); - - tatum::EdgeId tedge = timing_ctx.graph->find_edge(src_tnode, sink_tnode); - tatum::EdgeType edge_type = timing_ctx.graph->edge_type(tedge); - - ClusterNetId net_id = ClusterNetId::INVALID(); - - //We currently only trace interconnect edges in detail, and treat all others - //as flylines - if (edge_type == tatum::EdgeType::INTERCONNECT) { - //All atom pins are implemented inside CLBs, so next hop is to the top-level CLB pins - - //TODO: most of this code is highly similar to code in PostClusterDelayCalculator, refactor - // into a common method for walking the clustered netlist, this would also (potentially) - // allow us to grab the component delays - AtomBlockId atom_src_block = atom_ctx.nlist.pin_block(atom_src_pin); - AtomBlockId atom_sink_block = atom_ctx.nlist.pin_block(atom_sink_pin); - - ClusterBlockId clb_src_block = atom_ctx.lookup.atom_clb(atom_src_block); - VTR_ASSERT(clb_src_block != ClusterBlockId::INVALID()); - ClusterBlockId clb_sink_block = atom_ctx.lookup.atom_clb( - atom_sink_block); - VTR_ASSERT(clb_sink_block != ClusterBlockId::INVALID()); - - const t_pb_graph_pin *sink_gpin = atom_ctx.lookup.atom_pin_pb_graph_pin( - atom_sink_pin); - VTR_ASSERT(sink_gpin); - - int sink_pb_route_id = sink_gpin->pin_count_in_cluster; - - int sink_block_pin_index = -1; - int sink_net_pin_index = -1; - - std::tie(net_id, sink_block_pin_index, sink_net_pin_index) = - find_pb_route_clb_input_net_pin(clb_sink_block, - sink_pb_route_id); - if (net_id != ClusterNetId::INVALID() && sink_block_pin_index != -1 - && sink_net_pin_index != -1) { - //Connection leaves the CLB - //Now that we have the CLB source and sink pins, we need to grab all the points on the routing connecting the pins - VTR_ASSERT( - cluster_ctx.clb_nlist.net_driver_block(net_id) - == clb_src_block); - - std::vector routed_rr_nodes = trace_routed_connection_rr_nodes( - net_id, 0, sink_net_pin_index); - - //Mark all the nodes highlighted - t_draw_state *draw_state = get_draw_state_vars(); - for (int inode : routed_rr_nodes) { - draw_state->draw_rr_node[inode].color = color; - } - - draw_partial_route((std::vector) routed_rr_nodes, - (ezgl::renderer*) g); - } else { - //Connection entirely within the CLB, we don't draw the internal routing so treat it as a fly-line - VTR_ASSERT(clb_src_block == clb_sink_block); - } - } - - points.push_back(atom_pin_draw_coord(atom_sink_pin)); + tatum::NodeId sink_tnode, + ezgl::color color, + ezgl::renderer* g) { + auto& atom_ctx = g_vpr_ctx.atom(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& timing_ctx = g_vpr_ctx.timing(); + + AtomPinId atom_src_pin = atom_ctx.lookup.tnode_atom_pin(src_tnode); + AtomPinId atom_sink_pin = atom_ctx.lookup.tnode_atom_pin(sink_tnode); + + std::vector points; + points.push_back(atom_pin_draw_coord(atom_src_pin)); + + tatum::EdgeId tedge = timing_ctx.graph->find_edge(src_tnode, sink_tnode); + tatum::EdgeType edge_type = timing_ctx.graph->edge_type(tedge); + + ClusterNetId net_id = ClusterNetId::INVALID(); + + //We currently only trace interconnect edges in detail, and treat all others + //as flylines + if (edge_type == tatum::EdgeType::INTERCONNECT) { + //All atom pins are implemented inside CLBs, so next hop is to the top-level CLB pins + + //TODO: most of this code is highly similar to code in PostClusterDelayCalculator, refactor + // into a common method for walking the clustered netlist, this would also (potentially) + // allow us to grab the component delays + AtomBlockId atom_src_block = atom_ctx.nlist.pin_block(atom_src_pin); + AtomBlockId atom_sink_block = atom_ctx.nlist.pin_block(atom_sink_pin); + + ClusterBlockId clb_src_block = atom_ctx.lookup.atom_clb(atom_src_block); + VTR_ASSERT(clb_src_block != ClusterBlockId::INVALID()); + ClusterBlockId clb_sink_block = atom_ctx.lookup.atom_clb( + atom_sink_block); + VTR_ASSERT(clb_sink_block != ClusterBlockId::INVALID()); + + const t_pb_graph_pin* sink_gpin = atom_ctx.lookup.atom_pin_pb_graph_pin( + atom_sink_pin); + VTR_ASSERT(sink_gpin); + + int sink_pb_route_id = sink_gpin->pin_count_in_cluster; + + int sink_block_pin_index = -1; + int sink_net_pin_index = -1; + + std::tie(net_id, sink_block_pin_index, sink_net_pin_index) = find_pb_route_clb_input_net_pin(clb_sink_block, + sink_pb_route_id); + if (net_id != ClusterNetId::INVALID() && sink_block_pin_index != -1 + && sink_net_pin_index != -1) { + //Connection leaves the CLB + //Now that we have the CLB source and sink pins, we need to grab all the points on the routing connecting the pins + VTR_ASSERT( + cluster_ctx.clb_nlist.net_driver_block(net_id) + == clb_src_block); + + std::vector routed_rr_nodes = trace_routed_connection_rr_nodes( + net_id, 0, sink_net_pin_index); + + //Mark all the nodes highlighted + t_draw_state* draw_state = get_draw_state_vars(); + for (int inode : routed_rr_nodes) { + draw_state->draw_rr_node[inode].color = color; + } + + draw_partial_route((std::vector)routed_rr_nodes, + (ezgl::renderer*)g); + } else { + //Connection entirely within the CLB, we don't draw the internal routing so treat it as a fly-line + VTR_ASSERT(clb_src_block == clb_sink_block); + } + } + + points.push_back(atom_pin_draw_coord(atom_sink_pin)); } //Returns the set of rr nodes which connect driver to sink static std::vector trace_routed_connection_rr_nodes( - const ClusterNetId net_id, const int driver_pin, const int sink_pin) { - auto &route_ctx = g_vpr_ctx.routing(); + const ClusterNetId net_id, + const int driver_pin, + const int sink_pin) { + auto& route_ctx = g_vpr_ctx.routing(); - bool allocated_route_tree_structs = alloc_route_tree_timing_structs(true); //Needed for traceback_to_route_tree + bool allocated_route_tree_structs = alloc_route_tree_timing_structs(true); //Needed for traceback_to_route_tree - //Conver the traceback into an easily search-able - t_rt_node *rt_root = traceback_to_route_tree(net_id); + //Conver the traceback into an easily search-able + t_rt_node* rt_root = traceback_to_route_tree(net_id); - VTR_ASSERT( - rt_root - && rt_root->inode - == route_ctx.net_rr_terminals[net_id][driver_pin]); + VTR_ASSERT( + rt_root + && rt_root->inode + == route_ctx.net_rr_terminals[net_id][driver_pin]); - int sink_rr_node = route_ctx.net_rr_terminals[net_id][sink_pin]; + int sink_rr_node = route_ctx.net_rr_terminals[net_id][sink_pin]; - std::vector rr_nodes_on_path; + std::vector rr_nodes_on_path; - //Collect the rr nodes - trace_routed_connection_rr_nodes_recurr(rt_root, sink_rr_node, - rr_nodes_on_path); + //Collect the rr nodes + trace_routed_connection_rr_nodes_recurr(rt_root, sink_rr_node, + rr_nodes_on_path); - //Traced from sink to source, but we want to draw from source to sink - std::reverse(rr_nodes_on_path.begin(), rr_nodes_on_path.end()); + //Traced from sink to source, but we want to draw from source to sink + std::reverse(rr_nodes_on_path.begin(), rr_nodes_on_path.end()); - free_route_tree(rt_root); + free_route_tree(rt_root); - if (allocated_route_tree_structs) { - free_route_tree_timing_structs(); - } - return rr_nodes_on_path; + if (allocated_route_tree_structs) { + free_route_tree_timing_structs(); + } + return rr_nodes_on_path; } //Helper function for trace_routed_connection_rr_nodes //Adds the rr nodes linking rt_node to sink_rr_node to rr_nodes_on_path //Returns true if rt_node is on the path -bool trace_routed_connection_rr_nodes_recurr(const t_rt_node *rt_node, - int sink_rr_node, std::vector &rr_nodes_on_path) { - //DFS from the current rt_node to the sink_rr_node, when the sink is found trace back the used rr nodes - - if (rt_node->inode == sink_rr_node) { - rr_nodes_on_path.push_back(sink_rr_node); - return true; - } - - for (t_linked_rt_edge *edge = rt_node->u.child_list; edge != nullptr; edge = - edge->next) { - t_rt_node *child_rt_node = edge->child; - VTR_ASSERT(child_rt_node); - - bool on_path_to_sink = trace_routed_connection_rr_nodes_recurr( - child_rt_node, sink_rr_node, rr_nodes_on_path); - - if (on_path_to_sink) { - rr_nodes_on_path.push_back(rt_node->inode); - return true; - } - } - - return false; //Not on path to sink +bool trace_routed_connection_rr_nodes_recurr(const t_rt_node* rt_node, + int sink_rr_node, + std::vector& rr_nodes_on_path) { + //DFS from the current rt_node to the sink_rr_node, when the sink is found trace back the used rr nodes + + if (rt_node->inode == sink_rr_node) { + rr_nodes_on_path.push_back(sink_rr_node); + return true; + } + + for (t_linked_rt_edge* edge = rt_node->u.child_list; edge != nullptr; edge = edge->next) { + t_rt_node* child_rt_node = edge->child; + VTR_ASSERT(child_rt_node); + + bool on_path_to_sink = trace_routed_connection_rr_nodes_recurr( + child_rt_node, sink_rr_node, rr_nodes_on_path); + + if (on_path_to_sink) { + rr_nodes_on_path.push_back(rt_node->inode); + return true; + } + } + + return false; //Not on path to sink } //Find the edge between two rr nodes static t_edge_size find_edge(int prev_inode, int inode) { - auto &device_ctx = g_vpr_ctx.device(); - for (t_edge_size iedge = 0; - iedge < device_ctx.rr_nodes[prev_inode].num_edges(); ++iedge) { - if (device_ctx.rr_nodes[prev_inode].edge_sink_node(iedge) == inode) { - return iedge; - } - } - VTR_ASSERT(false); - return OPEN; + auto& device_ctx = g_vpr_ctx.device(); + for (t_edge_size iedge = 0; + iedge < device_ctx.rr_nodes[prev_inode].num_edges(); ++iedge) { + if (device_ctx.rr_nodes[prev_inode].edge_sink_node(iedge) == inode) { + return iedge; + } + } + VTR_ASSERT(false); + return OPEN; } ezgl::color to_ezgl_color(vtr::Color color) { - return ezgl::color(color.r * 255, color.g * 255, color.b * 255); + return ezgl::color(color.r * 255, color.g * 255, color.b * 255); } -static void draw_color_map_legend(const vtr::ColorMap &cmap, - ezgl::renderer *g) { - constexpr float LEGEND_WIDTH_FAC = 0.075; - constexpr float LEGEND_VERT_OFFSET_FAC = 0.05; - constexpr float TEXT_OFFSET = 10; - constexpr size_t NUM_COLOR_POINTS = 1000; - - g->set_coordinate_system(ezgl::SCREEN); - - float screen_width = application.get_canvas( - application.get_main_canvas_id())->width(); - float screen_height = application.get_canvas( - application.get_main_canvas_id())->height(); - float vert_offset = screen_height * LEGEND_VERT_OFFSET_FAC; - float legend_width = std::min(LEGEND_WIDTH_FAC * screen_width, 100); - - // In SCREEN coordinate: bottom_left is (0,0), right_top is (screen_width, screen_height) - ezgl::rectangle legend( { 0, vert_offset }, - { legend_width, screen_height - vert_offset }); - - float range = cmap.max() - cmap.min(); - float height_incr = legend.height() / float(NUM_COLOR_POINTS); - for (size_t i = 0; i < NUM_COLOR_POINTS; ++i) { - float val = cmap.min() + (float(i) / NUM_COLOR_POINTS) * range; - ezgl::color color = to_ezgl_color(cmap.color(val)); - - g->set_color(color); - g->fill_rectangle( { legend.left(), legend.top() - i * height_incr }, { - legend.right(), legend.top() - (i + 1) * height_incr }); - } - - //Min mark - g->set_color(blk_SKYBLUE); // set to skyblue so its easier to see - std::string str = vtr::string_fmt("%.3g", cmap.min()); - g->draw_text( { legend.center_x(), legend.top() - TEXT_OFFSET }, - str.c_str()); - - //Mid marker - g->set_color(ezgl::BLACK); - str = vtr::string_fmt("%.3g", cmap.min() + (cmap.range() / 2.)); - g->draw_text( { legend.center_x(), legend.center_y() }, str.c_str()); - - //Max marker - g->set_color(ezgl::BLACK); - str = vtr::string_fmt("%.3g", cmap.max()); - g->draw_text( { legend.center_x(), legend.bottom() + TEXT_OFFSET }, - str.c_str()); - - g->set_color(ezgl::BLACK); - g->draw_rectangle(legend); - - g->set_coordinate_system(ezgl::WORLD); +static void draw_color_map_legend(const vtr::ColorMap& cmap, + ezgl::renderer* g) { + constexpr float LEGEND_WIDTH_FAC = 0.075; + constexpr float LEGEND_VERT_OFFSET_FAC = 0.05; + constexpr float TEXT_OFFSET = 10; + constexpr size_t NUM_COLOR_POINTS = 1000; + + g->set_coordinate_system(ezgl::SCREEN); + + float screen_width = application.get_canvas( + application.get_main_canvas_id()) + ->width(); + float screen_height = application.get_canvas( + application.get_main_canvas_id()) + ->height(); + float vert_offset = screen_height * LEGEND_VERT_OFFSET_FAC; + float legend_width = std::min(LEGEND_WIDTH_FAC * screen_width, 100); + + // In SCREEN coordinate: bottom_left is (0,0), right_top is (screen_width, screen_height) + ezgl::rectangle legend({0, vert_offset}, + {legend_width, screen_height - vert_offset}); + + float range = cmap.max() - cmap.min(); + float height_incr = legend.height() / float(NUM_COLOR_POINTS); + for (size_t i = 0; i < NUM_COLOR_POINTS; ++i) { + float val = cmap.min() + (float(i) / NUM_COLOR_POINTS) * range; + ezgl::color color = to_ezgl_color(cmap.color(val)); + + g->set_color(color); + g->fill_rectangle({legend.left(), legend.top() - i * height_incr}, {legend.right(), legend.top() - (i + 1) * height_incr}); + } + + //Min mark + g->set_color(blk_SKYBLUE); // set to skyblue so its easier to see + std::string str = vtr::string_fmt("%.3g", cmap.min()); + g->draw_text({legend.center_x(), legend.top() - TEXT_OFFSET}, + str.c_str()); + + //Mid marker + g->set_color(ezgl::BLACK); + str = vtr::string_fmt("%.3g", cmap.min() + (cmap.range() / 2.)); + g->draw_text({legend.center_x(), legend.center_y()}, str.c_str()); + + //Max marker + g->set_color(ezgl::BLACK); + str = vtr::string_fmt("%.3g", cmap.max()); + g->draw_text({legend.center_x(), legend.bottom() + TEXT_OFFSET}, + str.c_str()); + + g->set_color(ezgl::BLACK); + g->draw_rectangle(legend); + + g->set_coordinate_system(ezgl::WORLD); } ezgl::color get_block_type_color(t_physical_tile_type_ptr type) { - //Wrap around if there are too many blocks - // This ensures we support an arbitrary number of types, - // although the colours may repeat - ezgl::color color = block_colors[type->index % block_colors.size()]; + //Wrap around if there are too many blocks + // This ensures we support an arbitrary number of types, + // although the colours may repeat + ezgl::color color = block_colors[type->index % block_colors.size()]; - return color; + return color; } //Lightens a color's luminance [0, 1] by an aboslute 'amount' ezgl::color lighten_color(ezgl::color color, float amount) { - constexpr double MAX_LUMINANCE = 0.95; //Clip luminance so it doesn't go full white - auto hsl = color2hsl(color); + constexpr double MAX_LUMINANCE = 0.95; //Clip luminance so it doesn't go full white + auto hsl = color2hsl(color); - hsl.l = std::max(0., std::min(MAX_LUMINANCE, hsl.l + amount)); + hsl.l = std::max(0., std::min(MAX_LUMINANCE, hsl.l + amount)); - return hsl2color(hsl); + return hsl2color(hsl); } static void draw_block_pin_util() { - t_draw_state *draw_state = get_draw_state_vars(); - if (draw_state->show_blk_pin_util == DRAW_NO_BLOCK_PIN_UTIL) - return; - - auto &device_ctx = g_vpr_ctx.device(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - - std::map total_input_pins; - std::map total_output_pins; - for (const auto &type : device_ctx.physical_tile_types) { - if (is_empty_type(&type)) { - continue; - } - - total_input_pins[&type] = type.num_input_pins + type.num_clock_pins; - total_output_pins[&type] = type.num_output_pins; - } - - auto blks = cluster_ctx.clb_nlist.blocks(); - vtr::vector pin_util(blks.size()); - for (auto blk : blks) { - auto type = physical_tile_type(blk); - - if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { - pin_util[blk] = cluster_ctx.clb_nlist.block_pins(blk).size() - / float(total_input_pins[type] + total_output_pins[type]); - } else if (draw_state->show_blk_pin_util - == DRAW_BLOCK_PIN_UTIL_INPUTS) { - pin_util[blk] = (cluster_ctx.clb_nlist.block_input_pins(blk).size() - + cluster_ctx.clb_nlist.block_clock_pins(blk).size()) - / float(total_input_pins[type]); - } else if (draw_state->show_blk_pin_util - == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { - pin_util[blk] = - (cluster_ctx.clb_nlist.block_output_pins(blk).size()) - / float(total_output_pins[type]); - } else { - VTR_ASSERT(false); - } - } - - std::unique_ptr cmap = std::make_unique( - 0., 1.); - - for (auto blk : blks) { - ezgl::color color = to_ezgl_color(cmap->color(pin_util[blk])); - draw_state->set_block_color(blk, color); - } - - draw_state->color_map = std::move(cmap); - - if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { - application.update_message("Block Total Pin Utilization"); - } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_INPUTS) { - application.update_message("Block Input Pin Utilization"); - - } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { - application.update_message("Block Output Pin Utilization"); - } else { - VTR_ASSERT(false); - } + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->show_blk_pin_util == DRAW_NO_BLOCK_PIN_UTIL) + return; + + auto& device_ctx = g_vpr_ctx.device(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + + std::map total_input_pins; + std::map total_output_pins; + for (const auto& type : device_ctx.physical_tile_types) { + if (is_empty_type(&type)) { + continue; + } + + total_input_pins[&type] = type.num_input_pins + type.num_clock_pins; + total_output_pins[&type] = type.num_output_pins; + } + + auto blks = cluster_ctx.clb_nlist.blocks(); + vtr::vector pin_util(blks.size()); + for (auto blk : blks) { + auto type = physical_tile_type(blk); + + if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { + pin_util[blk] = cluster_ctx.clb_nlist.block_pins(blk).size() + / float(total_input_pins[type] + total_output_pins[type]); + } else if (draw_state->show_blk_pin_util + == DRAW_BLOCK_PIN_UTIL_INPUTS) { + pin_util[blk] = (cluster_ctx.clb_nlist.block_input_pins(blk).size() + + cluster_ctx.clb_nlist.block_clock_pins(blk).size()) + / float(total_input_pins[type]); + } else if (draw_state->show_blk_pin_util + == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { + pin_util[blk] = (cluster_ctx.clb_nlist.block_output_pins(blk).size()) + / float(total_output_pins[type]); + } else { + VTR_ASSERT(false); + } + } + + std::unique_ptr cmap = std::make_unique( + 0., 1.); + + for (auto blk : blks) { + ezgl::color color = to_ezgl_color(cmap->color(pin_util[blk])); + draw_state->set_block_color(blk, color); + } + + draw_state->color_map = std::move(cmap); + + if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_TOTAL) { + application.update_message("Block Total Pin Utilization"); + } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_INPUTS) { + application.update_message("Block Input Pin Utilization"); + + } else if (draw_state->show_blk_pin_util == DRAW_BLOCK_PIN_UTIL_OUTPUTS) { + application.update_message("Block Output Pin Utilization"); + } else { + VTR_ASSERT(false); + } } static void draw_reset_blk_colors() { - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto blks = cluster_ctx.clb_nlist.blocks(); - for (auto blk : blks) { - draw_reset_blk_color(blk); - } + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto blks = cluster_ctx.clb_nlist.blocks(); + for (auto blk : blks) { + draw_reset_blk_color(blk); + } } -static void draw_routing_util(ezgl::renderer *g) { - t_draw_state *draw_state = get_draw_state_vars(); - if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { - return; - } - - t_draw_coords *draw_coords = get_draw_coords_vars(); - auto &device_ctx = g_vpr_ctx.device(); - - auto chanx_usage = calculate_routing_usage(CHANX); - auto chany_usage = calculate_routing_usage(CHANY); - - auto chanx_avail = calculate_routing_avail(CHANX); - auto chany_avail = calculate_routing_avail(CHANY); - - float min_util = 0.; - float max_util = -std::numeric_limits::infinity(); - for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { - for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { - max_util = std::max(max_util, - routing_util(chanx_usage[x][y], chanx_avail[x][y])); - max_util = std::max(max_util, - routing_util(chany_usage[x][y], chany_avail[x][y])); - } - } - max_util = std::max(max_util, 1.f); - - std::unique_ptr cmap; - - if (draw_state->clip_routing_util) { - cmap = std::make_unique(0., 1.); - } else { - cmap = std::make_unique(min_util, max_util); - } - - float tile_width = draw_coords->get_tile_width(); - float tile_height = draw_coords->get_tile_height(); - - float ALPHA = 0.95; - if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_OVER_BLOCKS) { - ALPHA = 1.; - } - - for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { - for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { - float sb_util = 0; - float chanx_util = 0; - float chany_util = 0; - int chan_count = 0; - if (x > 0) { - chanx_util = routing_util(chanx_usage[x][y], chanx_avail[x][y]); - if (draw_state->clip_routing_util) { - chanx_util = std::min(chanx_util, 1.f); - } - ezgl::color chanx_color = to_ezgl_color( - cmap->color(chanx_util)); - chanx_color.alpha *= ALPHA; - g->set_color(chanx_color); - ezgl::rectangle bb( - { draw_coords->tile_x[x], draw_coords->tile_y[y] - + 1 * tile_height }, - { draw_coords->tile_x[x] + 1 * tile_width, - draw_coords->tile_y[y + 1] }); - g->fill_rectangle(bb); - - g->set_color(ezgl::BLACK); - if (draw_state->show_routing_util - == DRAW_ROUTING_UTIL_WITH_VALUE) { - g->draw_text(bb.center(), - vtr::string_fmt("%.2f", chanx_util).c_str(), - bb.width(), bb.height()); - } else if (draw_state->show_routing_util - == DRAW_ROUTING_UTIL_WITH_FORMULA) { - g->draw_text(bb.center(), - vtr::string_fmt("%.2f = %.0f / %.0f", chanx_util, - chanx_usage[x][y], chanx_avail[x][y]).c_str(), - bb.width(), bb.height()); - } - - sb_util += chanx_util; - ++chan_count; - } - - if (y > 0) { - chany_util = routing_util(chany_usage[x][y], chany_avail[x][y]); - if (draw_state->clip_routing_util) { - chany_util = std::min(chany_util, 1.f); - } - ezgl::color chany_color = to_ezgl_color( - cmap->color(chany_util)); - chany_color.alpha *= ALPHA; - g->set_color(chany_color); - ezgl::rectangle bb( { draw_coords->tile_x[x] + 1 * tile_width, - draw_coords->tile_y[y] }, - { draw_coords->tile_x[x + 1], draw_coords->tile_y[y] - + 1 * tile_height }); - g->fill_rectangle(bb); - - g->set_color(ezgl::BLACK); - if (draw_state->show_routing_util - == DRAW_ROUTING_UTIL_WITH_VALUE) { - g->draw_text(bb.center(), - vtr::string_fmt("%.2f", chany_util).c_str(), - bb.width(), bb.height()); - } else if (draw_state->show_routing_util - == DRAW_ROUTING_UTIL_WITH_FORMULA) { - g->draw_text(bb.center(), - vtr::string_fmt("%.2f = %.0f / %.0f", chany_util, - chany_usage[x][y], chany_avail[x][y]).c_str(), - bb.width(), bb.height()); - } - - sb_util += chany_util; - ++chan_count; - } - - //For now SB util is just average of surrounding channels - //TODO: calculate actual usage - sb_util += routing_util(chanx_usage[x + 1][y], - chanx_avail[x + 1][y]); - chan_count += 1; - sb_util += routing_util(chany_usage[x][y + 1], - chany_avail[x][y + 1]); - chan_count += 1; - - VTR_ASSERT(chan_count > 0); - sb_util /= chan_count; - if (draw_state->clip_routing_util) { - sb_util = std::min(sb_util, 1.f); - } - ezgl::color sb_color = to_ezgl_color(cmap->color(sb_util)); - sb_color.alpha *= ALPHA; - g->set_color(sb_color); - ezgl::rectangle bb( - { draw_coords->tile_x[x] + 1 * tile_width, - draw_coords->tile_y[y] + 1 * tile_height }, - { draw_coords->tile_x[x + 1], draw_coords->tile_y[y + 1] }); - g->fill_rectangle(bb); - - //Draw over blocks - if (draw_state->show_routing_util - == DRAW_ROUTING_UTIL_OVER_BLOCKS) { - if (x < device_ctx.grid.width() - 2 - && y < device_ctx.grid.height() - 2) { - ezgl::rectangle bb2( { draw_coords->tile_x[x + 1], - draw_coords->tile_y[y + 1] }, - { draw_coords->tile_x[x + 1] + 1 * tile_width, - draw_coords->tile_y[y + 1] + 1 * tile_width }); - g->fill_rectangle(bb2); - } - } - g->set_color(ezgl::BLACK); - if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_VALUE - || draw_state->show_routing_util - == DRAW_ROUTING_UTIL_WITH_FORMULA) { - g->draw_text(bb.center(), - vtr::string_fmt("%.2f", sb_util).c_str(), bb.width(), - bb.height()); - } - } - } - - draw_state->color_map = std::move(cmap); +static void draw_routing_util(ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->show_routing_util == DRAW_NO_ROUTING_UTIL) { + return; + } + + t_draw_coords* draw_coords = get_draw_coords_vars(); + auto& device_ctx = g_vpr_ctx.device(); + + auto chanx_usage = calculate_routing_usage(CHANX); + auto chany_usage = calculate_routing_usage(CHANY); + + auto chanx_avail = calculate_routing_avail(CHANX); + auto chany_avail = calculate_routing_avail(CHANY); + + float min_util = 0.; + float max_util = -std::numeric_limits::infinity(); + for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { + for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { + max_util = std::max(max_util, + routing_util(chanx_usage[x][y], chanx_avail[x][y])); + max_util = std::max(max_util, + routing_util(chany_usage[x][y], chany_avail[x][y])); + } + } + max_util = std::max(max_util, 1.f); + + std::unique_ptr cmap; + + if (draw_state->clip_routing_util) { + cmap = std::make_unique(0., 1.); + } else { + cmap = std::make_unique(min_util, max_util); + } + + float tile_width = draw_coords->get_tile_width(); + float tile_height = draw_coords->get_tile_height(); + + float ALPHA = 0.95; + if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_OVER_BLOCKS) { + ALPHA = 1.; + } + + for (size_t x = 0; x < device_ctx.grid.width() - 1; ++x) { + for (size_t y = 0; y < device_ctx.grid.height() - 1; ++y) { + float sb_util = 0; + float chanx_util = 0; + float chany_util = 0; + int chan_count = 0; + if (x > 0) { + chanx_util = routing_util(chanx_usage[x][y], chanx_avail[x][y]); + if (draw_state->clip_routing_util) { + chanx_util = std::min(chanx_util, 1.f); + } + ezgl::color chanx_color = to_ezgl_color( + cmap->color(chanx_util)); + chanx_color.alpha *= ALPHA; + g->set_color(chanx_color); + ezgl::rectangle bb( + {draw_coords->tile_x[x], draw_coords->tile_y[y] + + 1 * tile_height}, + {draw_coords->tile_x[x] + 1 * tile_width, + draw_coords->tile_y[y + 1]}); + g->fill_rectangle(bb); + + g->set_color(ezgl::BLACK); + if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_VALUE) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f", chanx_util).c_str(), + bb.width(), bb.height()); + } else if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_FORMULA) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f = %.0f / %.0f", chanx_util, + chanx_usage[x][y], chanx_avail[x][y]) + .c_str(), + bb.width(), bb.height()); + } + + sb_util += chanx_util; + ++chan_count; + } + + if (y > 0) { + chany_util = routing_util(chany_usage[x][y], chany_avail[x][y]); + if (draw_state->clip_routing_util) { + chany_util = std::min(chany_util, 1.f); + } + ezgl::color chany_color = to_ezgl_color( + cmap->color(chany_util)); + chany_color.alpha *= ALPHA; + g->set_color(chany_color); + ezgl::rectangle bb({draw_coords->tile_x[x] + 1 * tile_width, + draw_coords->tile_y[y]}, + {draw_coords->tile_x[x + 1], draw_coords->tile_y[y] + + 1 * tile_height}); + g->fill_rectangle(bb); + + g->set_color(ezgl::BLACK); + if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_VALUE) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f", chany_util).c_str(), + bb.width(), bb.height()); + } else if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_FORMULA) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f = %.0f / %.0f", chany_util, + chany_usage[x][y], chany_avail[x][y]) + .c_str(), + bb.width(), bb.height()); + } + + sb_util += chany_util; + ++chan_count; + } + + //For now SB util is just average of surrounding channels + //TODO: calculate actual usage + sb_util += routing_util(chanx_usage[x + 1][y], + chanx_avail[x + 1][y]); + chan_count += 1; + sb_util += routing_util(chany_usage[x][y + 1], + chany_avail[x][y + 1]); + chan_count += 1; + + VTR_ASSERT(chan_count > 0); + sb_util /= chan_count; + if (draw_state->clip_routing_util) { + sb_util = std::min(sb_util, 1.f); + } + ezgl::color sb_color = to_ezgl_color(cmap->color(sb_util)); + sb_color.alpha *= ALPHA; + g->set_color(sb_color); + ezgl::rectangle bb( + {draw_coords->tile_x[x] + 1 * tile_width, + draw_coords->tile_y[y] + 1 * tile_height}, + {draw_coords->tile_x[x + 1], draw_coords->tile_y[y + 1]}); + g->fill_rectangle(bb); + + //Draw over blocks + if (draw_state->show_routing_util + == DRAW_ROUTING_UTIL_OVER_BLOCKS) { + if (x < device_ctx.grid.width() - 2 + && y < device_ctx.grid.height() - 2) { + ezgl::rectangle bb2({draw_coords->tile_x[x + 1], + draw_coords->tile_y[y + 1]}, + {draw_coords->tile_x[x + 1] + 1 * tile_width, + draw_coords->tile_y[y + 1] + 1 * tile_width}); + g->fill_rectangle(bb2); + } + } + g->set_color(ezgl::BLACK); + if (draw_state->show_routing_util == DRAW_ROUTING_UTIL_WITH_VALUE + || draw_state->show_routing_util + == DRAW_ROUTING_UTIL_WITH_FORMULA) { + g->draw_text(bb.center(), + vtr::string_fmt("%.2f", sb_util).c_str(), bb.width(), + bb.height()); + } + } + } + + draw_state->color_map = std::move(cmap); } static float get_router_expansion_cost(const t_rr_node_route_inf node_inf, - e_draw_router_expansion_cost draw_router_expansion_cost) { - if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL - || draw_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { - return node_inf.path_cost; - } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN - || draw_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { - return node_inf.backward_path_cost; - } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED - || draw_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { - return node_inf.path_cost - node_inf.backward_path_cost; - } - - VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); -} + e_draw_router_expansion_cost draw_router_expansion_cost) { + if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_TOTAL + || draw_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { + return node_inf.path_cost; + } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_KNOWN + || draw_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { + return node_inf.backward_path_cost; + } else if (draw_router_expansion_cost == DRAW_ROUTER_EXPANSION_COST_EXPECTED + || draw_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { + return node_inf.path_cost - node_inf.backward_path_cost; + } -static void draw_router_expansion_costs(ezgl::renderer *g) { - t_draw_state *draw_state = get_draw_state_vars(); - if (draw_state->show_router_expansion_cost - == DRAW_NO_ROUTER_EXPANSION_COST) { - return; - } - - auto &device_ctx = g_vpr_ctx.device(); - auto &routing_ctx = g_vpr_ctx.routing(); - - std::vector rr_costs(device_ctx.rr_nodes.size()); - - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - float cost = get_router_expansion_cost( - routing_ctx.rr_node_route_inf[inode], - draw_state->show_router_expansion_cost); - rr_costs[inode] = cost; - } - - bool all_nan = true; - for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { - if (std::isinf(rr_costs[inode])) { - rr_costs[inode] = NAN; - } else { - all_nan = false; - } - } - - if (!all_nan) { - draw_rr_costs(g, rr_costs, false); - } - if (draw_state->show_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_TOTAL - || draw_state->show_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { - application.update_message( - "Routing Expected Total Cost (known + estimate)"); - } else if (draw_state->show_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_KNOWN - || draw_state->show_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { - application.update_message("Routing Known Cost (from source to node)"); - } else if (draw_state->show_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_EXPECTED - || draw_state->show_router_expansion_cost - == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { - application.update_message( - "Routing Expected Cost (from node to target)"); - } else { - VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); - } + VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); } +static void draw_router_expansion_costs(ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->show_router_expansion_cost + == DRAW_NO_ROUTER_EXPANSION_COST) { + return; + } + + auto& device_ctx = g_vpr_ctx.device(); + auto& routing_ctx = g_vpr_ctx.routing(); + + std::vector rr_costs(device_ctx.rr_nodes.size()); + + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + float cost = get_router_expansion_cost( + routing_ctx.rr_node_route_inf[inode], + draw_state->show_router_expansion_cost); + rr_costs[inode] = cost; + } + + bool all_nan = true; + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { + if (std::isinf(rr_costs[inode])) { + rr_costs[inode] = NAN; + } else { + all_nan = false; + } + } + + if (!all_nan) { + draw_rr_costs(g, rr_costs, false); + } + if (draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_TOTAL + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_TOTAL_WITH_EDGES) { + application.update_message( + "Routing Expected Total Cost (known + estimate)"); + } else if (draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_KNOWN + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_KNOWN_WITH_EDGES) { + application.update_message("Routing Known Cost (from source to node)"); + } else if (draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_EXPECTED + || draw_state->show_router_expansion_cost + == DRAW_ROUTER_EXPANSION_COST_EXPECTED_WITH_EDGES) { + application.update_message( + "Routing Expected Cost (from node to target)"); + } else { + VPR_THROW(VPR_ERROR_DRAW, "Invalid Router RR cost drawing type"); + } +} static void draw_rr_costs(ezgl::renderer* g, const std::vector& rr_costs, bool lowest_cost_first) { t_draw_state* draw_state = get_draw_state_vars(); @@ -4300,376 +4239,366 @@ static void draw_rr_costs(ezgl::renderer* g, const std::vector& rr_costs, draw_state->color_map = std::move(cmap); } -static void draw_placement_macros(ezgl::renderer *g) { - t_draw_state *draw_state = get_draw_state_vars(); - - if (draw_state->show_placement_macros == DRAW_NO_PLACEMENT_MACROS) { - return; - } - t_draw_coords *draw_coords = get_draw_coords_vars(); - - auto &place_ctx = g_vpr_ctx.placement(); - for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); ++imacro) { - const t_pl_macro *pl_macro = &place_ctx.pl_macros[imacro]; - - //TODO: for now we just draw the bounding box of the macro, which is incorrect for non-rectangular macros... - int xlow = std::numeric_limits::max(); - int ylow = std::numeric_limits::max(); - int xhigh = std::numeric_limits::min(); - int yhigh = std::numeric_limits::min(); - - int x_root = OPEN; - int y_root = OPEN; - for (size_t imember = 0; imember < pl_macro->members.size(); - ++imember) { - const t_pl_macro_member *member = &pl_macro->members[imember]; - - ClusterBlockId blk = member->blk_index; - - if (imember == 0) { - x_root = place_ctx.block_locs[blk].loc.x; - y_root = place_ctx.block_locs[blk].loc.y; - } - - int x = x_root + member->offset.x; - int y = y_root + member->offset.y; - - xlow = std::min(xlow, x); - ylow = std::min(ylow, y); - xhigh = std::max(xhigh, x + physical_tile_type(blk)->width); - yhigh = std::max(yhigh, y + physical_tile_type(blk)->height); - } - - double draw_xlow = draw_coords->tile_x[xlow]; - double draw_ylow = draw_coords->tile_y[ylow]; - double draw_xhigh = draw_coords->tile_x[xhigh]; - double draw_yhigh = draw_coords->tile_y[yhigh]; - - g->set_color(blk_RED); - g->draw_rectangle( { draw_xlow, draw_ylow }, - { draw_xhigh, draw_yhigh }); - - ezgl::color fill = blk_SKYBLUE; - fill.alpha *= 0.3; - g->set_color(fill); - g->fill_rectangle( { draw_xlow, draw_ylow }, - { draw_xhigh, draw_yhigh }); - } +static void draw_placement_macros(ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + + if (draw_state->show_placement_macros == DRAW_NO_PLACEMENT_MACROS) { + return; + } + t_draw_coords* draw_coords = get_draw_coords_vars(); + + auto& place_ctx = g_vpr_ctx.placement(); + for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); ++imacro) { + const t_pl_macro* pl_macro = &place_ctx.pl_macros[imacro]; + + //TODO: for now we just draw the bounding box of the macro, which is incorrect for non-rectangular macros... + int xlow = std::numeric_limits::max(); + int ylow = std::numeric_limits::max(); + int xhigh = std::numeric_limits::min(); + int yhigh = std::numeric_limits::min(); + + int x_root = OPEN; + int y_root = OPEN; + for (size_t imember = 0; imember < pl_macro->members.size(); + ++imember) { + const t_pl_macro_member* member = &pl_macro->members[imember]; + + ClusterBlockId blk = member->blk_index; + + if (imember == 0) { + x_root = place_ctx.block_locs[blk].loc.x; + y_root = place_ctx.block_locs[blk].loc.y; + } + + int x = x_root + member->offset.x; + int y = y_root + member->offset.y; + + xlow = std::min(xlow, x); + ylow = std::min(ylow, y); + xhigh = std::max(xhigh, x + physical_tile_type(blk)->width); + yhigh = std::max(yhigh, y + physical_tile_type(blk)->height); + } + + double draw_xlow = draw_coords->tile_x[xlow]; + double draw_ylow = draw_coords->tile_y[ylow]; + double draw_xhigh = draw_coords->tile_x[xhigh]; + double draw_yhigh = draw_coords->tile_y[yhigh]; + + g->set_color(blk_RED); + g->draw_rectangle({draw_xlow, draw_ylow}, + {draw_xhigh, draw_yhigh}); + + ezgl::color fill = blk_SKYBLUE; + fill.alpha *= 0.3; + g->set_color(fill); + g->fill_rectangle({draw_xlow, draw_ylow}, + {draw_xhigh, draw_yhigh}); + } } static void highlight_blocks(double x, double y) { - t_draw_coords *draw_coords = get_draw_coords_vars(); - - char msg[vtr::bufsize]; - ClusterBlockId clb_index = EMPTY_BLOCK_ID; - auto &device_ctx = g_vpr_ctx.device(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_ctx = g_vpr_ctx.placement(); - - /// determine block /// - ezgl::rectangle clb_bbox; - - // iterate over grid x - for (size_t i = 0; i < device_ctx.grid.width(); ++i) { - if (draw_coords->tile_x[i] > x) { - break; // we've gone to far in the x direction - } - // iterate over grid y - for (size_t j = 0; j < device_ctx.grid.height(); ++j) { - if (draw_coords->tile_y[j] > y) { - break; // we've gone to far in the y direction - } - // iterate over sub_blocks - const t_grid_tile *grid_tile = &device_ctx.grid[i][j]; - for (int k = 0; k < grid_tile->type->capacity; ++k) { - clb_index = place_ctx.grid_blocks[i][j].blocks[k]; - if (clb_index != EMPTY_BLOCK_ID) { - clb_bbox = draw_coords->get_absolute_clb_bbox(clb_index, - cluster_ctx.clb_nlist.block_type(clb_index)); - if (clb_bbox.contains( { x, y })) { - break; - } else { - clb_index = EMPTY_BLOCK_ID; - } - } - } - if (clb_index != EMPTY_BLOCK_ID) { - break; // we've found something - } - } - if (clb_index != EMPTY_BLOCK_ID) { - break; // we've found something - } - } - - if (clb_index == EMPTY_BLOCK_ID || clb_index == ClusterBlockId::INVALID()) { - //Nothing found - return; - } - - VTR_ASSERT(clb_index != EMPTY_BLOCK_ID); - - // note: this will clear the selected sub-block if show_blk_internal is 0, - // or if it doesn't find anything - ezgl::point2d point_in_clb = ezgl::point2d(x, y) - clb_bbox.bottom_left(); - highlight_sub_block(point_in_clb, clb_index, - cluster_ctx.clb_nlist.block_pb(clb_index)); - - if (get_selected_sub_block_info().has_selection()) { - t_pb *selected_subblock = - get_selected_sub_block_info().get_selected_pb(); - sprintf(msg, "sub-block %s (a \"%s\") selected", - selected_subblock->name, - selected_subblock->pb_graph_node->pb_type->name); - } else { - /* Highlight block and fan-in/fan-outs. */ - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), - clb_index); - sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index), - cluster_ctx.clb_nlist.block_name(clb_index).c_str(), - place_ctx.block_locs[clb_index].loc.x, - place_ctx.block_locs[clb_index].loc.y); - } - - //If manual moves is activated, then user can select block from the grid. - ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - if (manual_move_global->manual_move_flag) { - manual_move_global->user_highlighted_block = true; - if (!manual_move_global->mm_window_is_open) { - draw_manual_moves_window(std::to_string(size_t(clb_index))); - } - } - - application.update_message(msg); - application.refresh_drawing(); + t_draw_coords* draw_coords = get_draw_coords_vars(); -} -void set_net_alpha_value(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/) { - std::string fa(gtk_entry_get_text((GtkEntry*) widget)); - t_draw_state *draw_state = get_draw_state_vars(); - draw_state->net_alpha = std::stof(fa); - application.refresh_drawing(); -} + char msg[vtr::bufsize]; + ClusterBlockId clb_index = EMPTY_BLOCK_ID; + auto& device_ctx = g_vpr_ctx.device(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); -void set_net_alpha_value_with_enter(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/) { - std::string fa(gtk_entry_get_text((GtkEntry*) widget)); - t_draw_state *draw_state = get_draw_state_vars(); - draw_state->net_alpha = std::stof(fa); - application.refresh_drawing(); -} + /// determine block /// + ezgl::rectangle clb_bbox; -float get_net_alpha() { - t_draw_state *draw_state = get_draw_state_vars(); - return draw_state->net_alpha; -} + // iterate over grid x + for (size_t i = 0; i < device_ctx.grid.width(); ++i) { + if (draw_coords->tile_x[i] > x) { + break; // we've gone to far in the x direction + } + // iterate over grid y + for (size_t j = 0; j < device_ctx.grid.height(); ++j) { + if (draw_coords->tile_y[j] > y) { + break; // we've gone to far in the y direction + } + // iterate over sub_blocks + const t_grid_tile* grid_tile = &device_ctx.grid[i][j]; + for (int k = 0; k < grid_tile->type->capacity; ++k) { + clb_index = place_ctx.grid_blocks[i][j].blocks[k]; + if (clb_index != EMPTY_BLOCK_ID) { + clb_bbox = draw_coords->get_absolute_clb_bbox(clb_index, + cluster_ctx.clb_nlist.block_type(clb_index)); + if (clb_bbox.contains({x, y})) { + break; + } else { + clb_index = EMPTY_BLOCK_ID; + } + } + } + if (clb_index != EMPTY_BLOCK_ID) { + break; // we've found something + } + } + if (clb_index != EMPTY_BLOCK_ID) { + break; // we've found something + } + } + + if (clb_index == EMPTY_BLOCK_ID || clb_index == ClusterBlockId::INVALID()) { + //Nothing found + return; + } -static void setup_default_ezgl_callbacks(ezgl::application *app) { - // Connect press_proceed function to the Proceed button - GObject *proceed_button = app->get_object("ProceedButton"); - g_signal_connect(proceed_button, "clicked", G_CALLBACK(ezgl::press_proceed), - app); + VTR_ASSERT(clb_index != EMPTY_BLOCK_ID); - // Connect press_zoom_fit function to the Zoom-fit button - GObject *zoom_fit_button = app->get_object("ZoomFitButton"); - g_signal_connect(zoom_fit_button, "clicked", - G_CALLBACK(ezgl::press_zoom_fit), app); + // note: this will clear the selected sub-block if show_blk_internal is 0, + // or if it doesn't find anything + ezgl::point2d point_in_clb = ezgl::point2d(x, y) - clb_bbox.bottom_left(); + highlight_sub_block(point_in_clb, clb_index, + cluster_ctx.clb_nlist.block_pb(clb_index)); - // Connect Pause button - GObject *pause_button = app->get_object("PauseButton"); - g_signal_connect(pause_button, "clicked", G_CALLBACK(set_force_pause), app); + if (get_selected_sub_block_info().has_selection()) { + t_pb* selected_subblock = get_selected_sub_block_info().get_selected_pb(); + sprintf(msg, "sub-block %s (a \"%s\") selected", + selected_subblock->name, + selected_subblock->pb_graph_node->pb_type->name); + } else { + /* Highlight block and fan-in/fan-outs. */ + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), + clb_index); + sprintf(msg, "Block #%zu (%s) at (%d, %d) selected.", size_t(clb_index), + cluster_ctx.clb_nlist.block_name(clb_index).c_str(), + place_ctx.block_locs[clb_index].loc.x, + place_ctx.block_locs[clb_index].loc.y); + } - // Connect Block Outline checkbox - GObject *block_outline = app->get_object("blockOutline"); - g_signal_connect(block_outline, "toggled", G_CALLBACK(set_block_outline), - app); + //If manual moves is activated, then user can select block from the grid. + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + if (manual_move_global->manual_move_flag) { + manual_move_global->user_highlighted_block = true; + if (!manual_move_global->mm_window_is_open) { + draw_manual_moves_window(std::to_string(size_t(clb_index))); + } + } - // Connect Block Text checkbox - GObject *block_text = app->get_object("blockText"); - g_signal_connect(block_text, "toggled", G_CALLBACK(set_block_text), app); + application.update_message(msg); + application.refresh_drawing(); +} +void set_net_alpha_value(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { + std::string fa(gtk_entry_get_text((GtkEntry*)widget)); + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->net_alpha = std::stof(fa); + application.refresh_drawing(); +} - // Connect Clip Routing Util checkbox - GObject *clip_routing = app->get_object("clipRoutingUtil"); - g_signal_connect(clip_routing, "toggled", G_CALLBACK(clip_routing_util), - app); +void set_net_alpha_value_with_enter(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { + std::string fa(gtk_entry_get_text((GtkEntry*)widget)); + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->net_alpha = std::stof(fa); + application.refresh_drawing(); +} - // Connect Debug Button - GObject *debugger = app->get_object("debugButton"); - g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); +float get_net_alpha() { + t_draw_state* draw_state = get_draw_state_vars(); + return draw_state->net_alpha; +} +static void setup_default_ezgl_callbacks(ezgl::application* app) { + // Connect press_proceed function to the Proceed button + GObject* proceed_button = app->get_object("ProceedButton"); + g_signal_connect(proceed_button, "clicked", G_CALLBACK(ezgl::press_proceed), + app); + + // Connect press_zoom_fit function to the Zoom-fit button + GObject* zoom_fit_button = app->get_object("ZoomFitButton"); + g_signal_connect(zoom_fit_button, "clicked", + G_CALLBACK(ezgl::press_zoom_fit), app); + + // Connect Pause button + GObject* pause_button = app->get_object("PauseButton"); + g_signal_connect(pause_button, "clicked", G_CALLBACK(set_force_pause), app); + + // Connect Block Outline checkbox + GObject* block_outline = app->get_object("blockOutline"); + g_signal_connect(block_outline, "toggled", G_CALLBACK(set_block_outline), + app); + + // Connect Block Text checkbox + GObject* block_text = app->get_object("blockText"); + g_signal_connect(block_text, "toggled", G_CALLBACK(set_block_text), app); + + // Connect Clip Routing Util checkbox + GObject* clip_routing = app->get_object("clipRoutingUtil"); + g_signal_connect(clip_routing, "toggled", G_CALLBACK(clip_routing_util), + app); + + // Connect Debug Button + GObject* debugger = app->get_object("debugButton"); + g_signal_connect(debugger, "clicked", G_CALLBACK(draw_debug_window), NULL); } // Callback function for Block Outline checkbox -static void set_block_outline(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/) { - t_draw_state *draw_state = get_draw_state_vars(); - - // assign corresponding bool value to draw_state->draw_block_outlines - if (gtk_toggle_button_get_active((GtkToggleButton*) widget)) - draw_state->draw_block_outlines = true; - else - draw_state->draw_block_outlines = false; - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +static void set_block_outline(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { + t_draw_state* draw_state = get_draw_state_vars(); + + // assign corresponding bool value to draw_state->draw_block_outlines + if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) + draw_state->draw_block_outlines = true; + else + draw_state->draw_block_outlines = false; + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } // Callback function for Block Text checkbox -static void set_block_text(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/) { - t_draw_state *draw_state = get_draw_state_vars(); - - // assign corresponding bool value to draw_state->draw_block_text - if (gtk_toggle_button_get_active((GtkToggleButton*) widget)) - draw_state->draw_block_text = true; - else - draw_state->draw_block_text = false; - - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { + t_draw_state* draw_state = get_draw_state_vars(); + + // assign corresponding bool value to draw_state->draw_block_text + if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) + draw_state->draw_block_text = true; + else + draw_state->draw_block_text = false; + + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } // Callback function for Clip Routing Util checkbox -static void clip_routing_util(GtkWidget *widget, gint /*response_id*/, - gpointer /*data*/) { - t_draw_state *draw_state = get_draw_state_vars(); - - // assign corresponding bool value to draw_state->clip_routing_util - if (gtk_toggle_button_get_active((GtkToggleButton*) widget)) - draw_state->clip_routing_util = true; - else - draw_state->clip_routing_util = false; - - //redraw - application.update_message(draw_state->default_message); - application.refresh_drawing(); +static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) { + t_draw_state* draw_state = get_draw_state_vars(); + + // assign corresponding bool value to draw_state->clip_routing_util + if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) + draw_state->clip_routing_util = true; + else + draw_state->clip_routing_util = false; + + //redraw + application.update_message(draw_state->default_message); + application.refresh_drawing(); } // Callback function for NetMax Fanout checkbox -void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - /* this is the callback function for runtime created net_max_fanout widget - * which is written in button.cpp */ - std::string button_name = "netMaxFanout"; - auto max_fanout = find_button(button_name.c_str()); - t_draw_state *draw_state = get_draw_state_vars(); - - //set draw_state->draw_net_max_fanout to its corresponding value in the ui - int new_value = gtk_spin_button_get_value_as_int( - (GtkSpinButton*) max_fanout); - draw_state->draw_net_max_fanout = new_value; - - //redraw - application.refresh_drawing(); +void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created net_max_fanout widget + * which is written in button.cpp */ + std::string button_name = "netMaxFanout"; + auto max_fanout = find_button(button_name.c_str()); + t_draw_state* draw_state = get_draw_state_vars(); + + //set draw_state->draw_net_max_fanout to its corresponding value in the ui + int new_value = gtk_spin_button_get_value_as_int( + (GtkSpinButton*)max_fanout); + draw_state->draw_net_max_fanout = new_value; + + //redraw + application.refresh_drawing(); } -static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, - gpointer /*data*/) { - t_draw_state *draw_state = get_draw_state_vars(); +static void set_force_pause(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + t_draw_state* draw_state = get_draw_state_vars(); - draw_state->forced_pause = true; + draw_state->forced_pause = true; } static void run_graphics_commands(std::string commands) { - //A very simmple command interpreter for scripting graphics - t_draw_state *draw_state = get_draw_state_vars(); - - t_draw_state backup_draw_state = *draw_state; - - std::vector> cmds; - for (std::string raw_cmd : vtr::split(commands, ";")) { - cmds.push_back(vtr::split(raw_cmd)); - } - - for (auto &cmd : cmds) { - VTR_ASSERT_MSG(cmd.size() > 0, "Expect non-empty graphics commands"); - - for (auto &item : cmd) { - VTR_LOG("%s ", item.c_str()); - } - VTR_LOG("\n"); - - if (cmd[0] == "save_graphics") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect filename after 'save_graphics'"); - - auto name_ext = vtr::split_ext(cmd[1]); - - //Replace {i} with the sequence number - std::string name = vtr::replace_all(name_ext[0], "{i}", - std::to_string(draw_state->sequence_number)); - - save_graphics(/*extension=*/name_ext[1], /*filename=*/name); - VTR_LOG("Saving to %s\n", std::string(name + name_ext[1]).c_str()); - - } else if (cmd[0] == "set_macros") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect net draw state after 'set_macro'"); - draw_state->show_placement_macros = - (e_draw_placement_macros) vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->show_placement_macros); - } else if (cmd[0] == "set_nets") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect net draw state after 'set_nets'"); - draw_state->show_nets = (e_draw_nets) vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->show_nets); - } else if (cmd[0] == "set_cpd") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect cpd draw state after 'set_cpd'"); - draw_state->show_crit_path = (e_draw_crit_path) vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->show_crit_path); - } else if (cmd[0] == "set_routing_util") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect routing util draw state after 'set_routing_util'"); - draw_state->show_routing_util = (e_draw_routing_util) vtr::atoi( - cmd[1]); - VTR_LOG("%d\n", (int )draw_state->show_routing_util); - } else if (cmd[0] == "set_clip_routing_util") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect routing util draw state after 'set_routing_util'"); - draw_state->clip_routing_util = (bool) vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->clip_routing_util); - } else if (cmd[0] == "set_congestion") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect congestion draw state after 'set_congestion'"); - draw_state->show_congestion = (e_draw_congestion) vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->show_congestion); - } else if (cmd[0] == "set_draw_block_outlines") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect draw block outlines state after 'set_draw_block_outlines'"); - draw_state->draw_block_outlines = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->draw_block_outlines); - } else if (cmd[0] == "set_draw_block_text") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect draw block text state after 'set_draw_block_text'"); - draw_state->draw_block_text = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->draw_block_text); - } else if (cmd[0] == "set_draw_block_internals") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect draw state after 'set_draw_block_internals'"); - draw_state->show_blk_internal = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->show_blk_internal); - } else if (cmd[0] == "set_draw_net_max_fanout") { - VTR_ASSERT_MSG(cmd.size() == 2, - "Expect maximum fanout after 'set_draw_net_max_fanout'"); - draw_state->draw_net_max_fanout = vtr::atoi(cmd[1]); - VTR_LOG("%d\n", (int )draw_state->draw_net_max_fanout); - } else if (cmd[0] == "exit") { - VTR_ASSERT_MSG(cmd.size() == 2, "Expect exit code after 'exit'"); - exit(vtr::atoi(cmd[1])); - } else { - VPR_ERROR(VPR_ERROR_DRAW, - vtr::string_fmt("Unrecognized graphics command '%s'", - cmd[0].c_str()).c_str()); - } - } - - *draw_state = backup_draw_state; //Restor original draw state - - //Advance the sequence number - ++draw_state->sequence_number; + //A very simmple command interpreter for scripting graphics + t_draw_state* draw_state = get_draw_state_vars(); + + t_draw_state backup_draw_state = *draw_state; + + std::vector> cmds; + for (std::string raw_cmd : vtr::split(commands, ";")) { + cmds.push_back(vtr::split(raw_cmd)); + } + + for (auto& cmd : cmds) { + VTR_ASSERT_MSG(cmd.size() > 0, "Expect non-empty graphics commands"); + + for (auto& item : cmd) { + VTR_LOG("%s ", item.c_str()); + } + VTR_LOG("\n"); + + if (cmd[0] == "save_graphics") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect filename after 'save_graphics'"); + + auto name_ext = vtr::split_ext(cmd[1]); + + //Replace {i} with the sequence number + std::string name = vtr::replace_all(name_ext[0], "{i}", + std::to_string(draw_state->sequence_number)); + + save_graphics(/*extension=*/name_ext[1], /*filename=*/name); + VTR_LOG("Saving to %s\n", std::string(name + name_ext[1]).c_str()); + + } else if (cmd[0] == "set_macros") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect net draw state after 'set_macro'"); + draw_state->show_placement_macros = (e_draw_placement_macros)vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->show_placement_macros); + } else if (cmd[0] == "set_nets") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect net draw state after 'set_nets'"); + draw_state->show_nets = (e_draw_nets)vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->show_nets); + } else if (cmd[0] == "set_cpd") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect cpd draw state after 'set_cpd'"); + draw_state->show_crit_path = (e_draw_crit_path)vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->show_crit_path); + } else if (cmd[0] == "set_routing_util") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect routing util draw state after 'set_routing_util'"); + draw_state->show_routing_util = (e_draw_routing_util)vtr::atoi( + cmd[1]); + VTR_LOG("%d\n", (int)draw_state->show_routing_util); + } else if (cmd[0] == "set_clip_routing_util") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect routing util draw state after 'set_routing_util'"); + draw_state->clip_routing_util = (bool)vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->clip_routing_util); + } else if (cmd[0] == "set_congestion") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect congestion draw state after 'set_congestion'"); + draw_state->show_congestion = (e_draw_congestion)vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->show_congestion); + } else if (cmd[0] == "set_draw_block_outlines") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect draw block outlines state after 'set_draw_block_outlines'"); + draw_state->draw_block_outlines = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->draw_block_outlines); + } else if (cmd[0] == "set_draw_block_text") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect draw block text state after 'set_draw_block_text'"); + draw_state->draw_block_text = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->draw_block_text); + } else if (cmd[0] == "set_draw_block_internals") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect draw state after 'set_draw_block_internals'"); + draw_state->show_blk_internal = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->show_blk_internal); + } else if (cmd[0] == "set_draw_net_max_fanout") { + VTR_ASSERT_MSG(cmd.size() == 2, + "Expect maximum fanout after 'set_draw_net_max_fanout'"); + draw_state->draw_net_max_fanout = vtr::atoi(cmd[1]); + VTR_LOG("%d\n", (int)draw_state->draw_net_max_fanout); + } else if (cmd[0] == "exit") { + VTR_ASSERT_MSG(cmd.size() == 2, "Expect exit code after 'exit'"); + exit(vtr::atoi(cmd[1])); + } else { + VPR_ERROR(VPR_ERROR_DRAW, + vtr::string_fmt("Unrecognized graphics command '%s'", + cmd[0].c_str()) + .c_str()); + } + } + + *draw_state = backup_draw_state; //Restor original draw state + + //Advance the sequence number + ++draw_state->sequence_number; } /* This routine highlights the blocks affected in the latest move * @@ -4677,67 +4606,67 @@ static void run_graphics_commands(std::string commands) { * It also highlights the moved block input and output terminals * * Currently, it is used in placer debugger when breakpoint is reached */ void highlight_moved_block_and_its_terminals( - const t_pl_blocks_to_be_moved &blocks_affected) { - auto &cluster_ctx = g_vpr_ctx.clustering(); - - //clear all selected blocks - deselect_all(); - - //highlight the input/output terminals of the moved block - draw_highlight_blocks_color( - cluster_ctx.clb_nlist.block_type( - blocks_affected.moved_blocks[0].block_num), - blocks_affected.moved_blocks[0].block_num); - - //highlight the old and new locations of the moved block - clear_colored_locations(); - set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, - OLD_BLK_LOC_COLOR); - set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, - NEW_BLK_LOC_COLOR); + const t_pl_blocks_to_be_moved& blocks_affected) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + + //clear all selected blocks + deselect_all(); + + //highlight the input/output terminals of the moved block + draw_highlight_blocks_color( + cluster_ctx.clb_nlist.block_type( + blocks_affected.moved_blocks[0].block_num), + blocks_affected.moved_blocks[0].block_num); + + //highlight the old and new locations of the moved block + clear_colored_locations(); + set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, + OLD_BLK_LOC_COLOR); + set_draw_loc_color(blocks_affected.moved_blocks[0].old_loc, + NEW_BLK_LOC_COLOR); } // pass in an (x,y,subtile) location and the color in which it should be drawn. // This overrides the color of any block placed in that location, and also applies if the location is empty. void set_draw_loc_color(t_pl_loc loc, ezgl::color clr) { - t_draw_state *draw_state = get_draw_state_vars(); - draw_state->colored_locations.push_back(std::make_pair(loc, clr)); + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->colored_locations.push_back(std::make_pair(loc, clr)); } // clear the colored_locations vector void clear_colored_locations() { - t_draw_state *draw_state = get_draw_state_vars(); - draw_state->colored_locations.clear(); + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->colored_locations.clear(); } // This routine takes in a (x,y) location. // If the input loc is marked in colored_locations vector, the function will return true and the correspnding color is sent back in loc_color // otherwise, the function returns false (the location isn't among the highlighted locations) -bool highlight_loc_with_specific_color(int x, int y, ezgl::color &loc_color) { - t_draw_state *draw_state = get_draw_state_vars(); - - //define a (x,y) location variable - t_pl_loc curr_loc; - curr_loc.x = x; - curr_loc.y = y; - - //search for the current location in the vector of colored locations - auto it = std::find_if(draw_state->colored_locations.begin(), - draw_state->colored_locations.end(), - [&curr_loc](const std::pair &vec_element) { - return (vec_element.first.x == curr_loc.x - && vec_element.first.y == curr_loc.y); - }); - - if (it != draw_state->colored_locations.end()) { - /* found a colored location at the spot I am drawing * - * (currently used for drawing the current move). * - * This overrides any block color. */ - loc_color = it->second; - return true; - } - - return false; +bool highlight_loc_with_specific_color(int x, int y, ezgl::color& loc_color) { + t_draw_state* draw_state = get_draw_state_vars(); + + //define a (x,y) location variable + t_pl_loc curr_loc; + curr_loc.x = x; + curr_loc.y = y; + + //search for the current location in the vector of colored locations + auto it = std::find_if(draw_state->colored_locations.begin(), + draw_state->colored_locations.end(), + [&curr_loc](const std::pair& vec_element) { + return (vec_element.first.x == curr_loc.x + && vec_element.first.y == curr_loc.y); + }); + + if (it != draw_state->colored_locations.end()) { + /* found a colored location at the spot I am drawing * + * (currently used for drawing the current move). * + * This overrides any block color. */ + loc_color = it->second; + return true; + } + + return false; } #endif /* NO_GRAPHICS */ diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 1750d3fb3b2..8f4c229a28c 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -3,7 +3,7 @@ #include "globals.h" #include "draw.h" #include "move_generator.h" -#include "buttons.h" +#include "buttons.h" #include "move_utils.h" #ifndef NO_GRAPHICS @@ -12,308 +12,298 @@ ManualMovesGlobals manual_moves_global; void draw_manual_moves_window(std::string block_id) { - - if (!manual_moves_global.mm_window_is_open) { - manual_moves_global.mm_window_is_open = true; - - //Window settings- - manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position((GtkWindow*) manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); - gtk_window_set_title((GtkWindow*) manual_moves_global.manual_move_window, "Manual Moves Generator"); - gtk_widget_set_name(manual_moves_global.manual_move_window, "manual_move_window"); - - GtkWidget *grid = gtk_grid_new(); - GtkWidget *block_entry = gtk_entry_new(); - - if (manual_moves_global.user_highlighted_block) { - gtk_entry_set_text((GtkEntry*) block_entry, block_id.c_str()); - manual_moves_global.user_highlighted_block = false; - } - - GtkWidget* x_position_entry = gtk_entry_new(); - GtkWidget* y_position_entry = gtk_entry_new(); - GtkWidget* subtile_position_entry = gtk_entry_new(); - GtkWidget* block_label = gtk_label_new("Block ID/Block Name:"); - GtkWidget* to_label = gtk_label_new("To Location:"); - GtkWidget* x = gtk_label_new("x:"); - GtkWidget* y = gtk_label_new("y:"); - GtkWidget* subtile = gtk_label_new("Subtile:"); - - GtkWidget* calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); - - //Add all to grid - gtk_grid_attach((GtkGrid*)grid, block_label, 0, 0, 1, 1); - gtk_grid_attach((GtkGrid*)grid, block_entry, 0, 1, 1, 1); - gtk_grid_attach((GtkGrid*)grid, to_label, 2, 0, 1, 1); - gtk_grid_attach((GtkGrid*)grid, x, 1, 1, 1, 1); - gtk_grid_attach((GtkGrid*)grid, x_position_entry, 2, 1, 1, 1); - gtk_grid_attach((GtkGrid*)grid, y, 1, 2, 1, 1); - gtk_grid_attach((GtkGrid*)grid, y_position_entry, 2, 2, 1, 1); - gtk_grid_attach((GtkGrid*)grid, subtile, 1, 3, 1, 1); - gtk_grid_attach((GtkGrid*)grid, subtile_position_entry, 2, 3, 1, 1); - gtk_grid_attach((GtkGrid*)grid, calculate_cost_button, 0, 4, 3, 1); //spans three columns - - //Set margins - gtk_widget_set_margin_bottom(grid, 20); - gtk_widget_set_margin_top(grid, 20); - gtk_widget_set_margin_start(grid, 20); - gtk_widget_set_margin_end(grid, 20); - gtk_widget_set_margin_bottom(block_label, 5); - gtk_widget_set_margin_bottom(to_label, 5); - gtk_widget_set_margin_top(calculate_cost_button, 15); - gtk_widget_set_margin_start(x, 13); - gtk_widget_set_margin_start(y, 13); - gtk_widget_set_halign(calculate_cost_button, GTK_ALIGN_CENTER); - - //connect signals - g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); - g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); - - - gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); - gtk_widget_show_all(manual_moves_global.manual_move_window); - } + if (!manual_moves_global.mm_window_is_open) { + manual_moves_global.mm_window_is_open = true; + + //Window settings- + manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position((GtkWindow*)manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*)manual_moves_global.manual_move_window, "Manual Moves Generator"); + gtk_widget_set_name(manual_moves_global.manual_move_window, "manual_move_window"); + + GtkWidget* grid = gtk_grid_new(); + GtkWidget* block_entry = gtk_entry_new(); + + if (manual_moves_global.user_highlighted_block) { + gtk_entry_set_text((GtkEntry*)block_entry, block_id.c_str()); + manual_moves_global.user_highlighted_block = false; + } + + GtkWidget* x_position_entry = gtk_entry_new(); + GtkWidget* y_position_entry = gtk_entry_new(); + GtkWidget* subtile_position_entry = gtk_entry_new(); + GtkWidget* block_label = gtk_label_new("Block ID/Block Name:"); + GtkWidget* to_label = gtk_label_new("To Location:"); + GtkWidget* x = gtk_label_new("x:"); + GtkWidget* y = gtk_label_new("y:"); + GtkWidget* subtile = gtk_label_new("Subtile:"); + + GtkWidget* calculate_cost_button = gtk_button_new_with_label("Calculate Costs"); + + //Add all to grid + gtk_grid_attach((GtkGrid*)grid, block_label, 0, 0, 1, 1); + gtk_grid_attach((GtkGrid*)grid, block_entry, 0, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, to_label, 2, 0, 1, 1); + gtk_grid_attach((GtkGrid*)grid, x, 1, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, x_position_entry, 2, 1, 1, 1); + gtk_grid_attach((GtkGrid*)grid, y, 1, 2, 1, 1); + gtk_grid_attach((GtkGrid*)grid, y_position_entry, 2, 2, 1, 1); + gtk_grid_attach((GtkGrid*)grid, subtile, 1, 3, 1, 1); + gtk_grid_attach((GtkGrid*)grid, subtile_position_entry, 2, 3, 1, 1); + gtk_grid_attach((GtkGrid*)grid, calculate_cost_button, 0, 4, 3, 1); //spans three columns + + //Set margins + gtk_widget_set_margin_bottom(grid, 20); + gtk_widget_set_margin_top(grid, 20); + gtk_widget_set_margin_start(grid, 20); + gtk_widget_set_margin_end(grid, 20); + gtk_widget_set_margin_bottom(block_label, 5); + gtk_widget_set_margin_bottom(to_label, 5); + gtk_widget_set_margin_top(calculate_cost_button, 15); + gtk_widget_set_margin_start(x, 13); + gtk_widget_set_margin_start(y, 13); + gtk_widget_set_halign(calculate_cost_button, GTK_ALIGN_CENTER); + + //connect signals + g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); + g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + + gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); + gtk_widget_show_all(manual_moves_global.manual_move_window); + } } void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { - - int block_id; - int x_location; - int y_location; - int subtile_location; - bool valid_input = true; - - //Loading the context/data structures needed. - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_ctx = g_vpr_ctx.placement(); - - //Getting entry values - GtkWidget *block_entry = gtk_grid_get_child_at((GtkGrid*) grid, 0, 1); - std::string block_id_string = gtk_entry_get_text((GtkEntry*) block_entry); - - if (string_is_a_number(block_id_string)) { //for block ID - block_id = std::atoi(block_id_string.c_str()); - } else { //for block name - block_id = size_t(cluster_ctx.clb_nlist.find_block(gtk_entry_get_text((GtkEntry*) block_entry))); - } - //if the block is not found - if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { - invalid_breakpoint_entry_window("Invalid block ID/Name"); - valid_input = false; - } - - GtkWidget *x_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 1); - GtkWidget *y_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 2); - GtkWidget *subtile_position_entry = gtk_grid_get_child_at((GtkGrid*) grid, 2, 3); - - x_location = std::atoi(gtk_entry_get_text((GtkEntry*) x_position_entry)); - y_location = std::atoi(gtk_entry_get_text((GtkEntry*) y_position_entry)); - subtile_location = std::atoi(gtk_entry_get_text((GtkEntry*) subtile_position_entry)); - - //Function in move_utils.cpp that returns true if the location swap is valid - t_pl_loc to = t_pl_loc(x_location, y_location, subtile_location); - if (!is_legal_swap_to_location(ClusterBlockId(block_id), to)) { - valid_input = false; - } - //If the block requested is already in that location. - ClusterBlockId current_block = ClusterBlockId(block_id); - t_pl_loc current_block_loc = place_ctx.block_locs[current_block].loc; - if (x_location == current_block_loc.x && y_location == current_block_loc.y && subtile_location == current_block_loc.sub_tile) { - invalid_breakpoint_entry_window("The block is currently in this location"); - valid_input = false; - } - //Checks if all fields from the user input window are complete. - if (std::string(gtk_entry_get_text((GtkEntry*) block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*) x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*) y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*) subtile_position_entry)).empty()) { - invalid_breakpoint_entry_window("Not all fields are complete"); - valid_input = false; - } - - if (valid_input) { - manual_moves_global.manual_move_info.valid_input = true; - manual_moves_global.manual_move_info.blockID = block_id; - manual_moves_global.manual_move_info.x_pos = x_location; - manual_moves_global.manual_move_info.y_pos = y_location; - manual_moves_global.manual_move_info.subtile = subtile_location; - manual_moves_global.manual_move_info.to_location = to; - - //Highlighting the block - deselect_all(); - ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); - application.refresh_drawing(); - - //Continues to move costs window. - GtkWidget *proceed = find_button("ProceedButton"); - ezgl::press_proceed(proceed, &application); - - } else { - manual_moves_global.manual_move_info.valid_input = false; - } + int block_id; + int x_location; + int y_location; + int subtile_location; + bool valid_input = true; + + //Loading the context/data structures needed. + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + + //Getting entry values + GtkWidget* block_entry = gtk_grid_get_child_at((GtkGrid*)grid, 0, 1); + std::string block_id_string = gtk_entry_get_text((GtkEntry*)block_entry); + + if (string_is_a_number(block_id_string)) { //for block ID + block_id = std::atoi(block_id_string.c_str()); + } else { //for block name + block_id = size_t(cluster_ctx.clb_nlist.find_block(gtk_entry_get_text((GtkEntry*)block_entry))); + } + //if the block is not found + if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { + invalid_breakpoint_entry_window("Invalid block ID/Name"); + valid_input = false; + } + + GtkWidget* x_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 1); + GtkWidget* y_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 2); + GtkWidget* subtile_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 3); + + x_location = std::atoi(gtk_entry_get_text((GtkEntry*)x_position_entry)); + y_location = std::atoi(gtk_entry_get_text((GtkEntry*)y_position_entry)); + subtile_location = std::atoi(gtk_entry_get_text((GtkEntry*)subtile_position_entry)); + + //Function in move_utils.cpp that returns true if the location swap is valid + t_pl_loc to = t_pl_loc(x_location, y_location, subtile_location); + if (!is_legal_swap_to_location(ClusterBlockId(block_id), to)) { + valid_input = false; + } + //If the block requested is already in that location. + ClusterBlockId current_block = ClusterBlockId(block_id); + t_pl_loc current_block_loc = place_ctx.block_locs[current_block].loc; + if (x_location == current_block_loc.x && y_location == current_block_loc.y && subtile_location == current_block_loc.sub_tile) { + invalid_breakpoint_entry_window("The block is currently in this location"); + valid_input = false; + } + //Checks if all fields from the user input window are complete. + if (std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { + invalid_breakpoint_entry_window("Not all fields are complete"); + valid_input = false; + } + + if (valid_input) { + manual_moves_global.manual_move_info.valid_input = true; + manual_moves_global.manual_move_info.blockID = block_id; + manual_moves_global.manual_move_info.x_pos = x_location; + manual_moves_global.manual_move_info.y_pos = y_location; + manual_moves_global.manual_move_info.subtile = subtile_location; + manual_moves_global.manual_move_info.to_location = to; + + //Highlighting the block + deselect_all(); + ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); + application.refresh_drawing(); + + //Continues to move costs window. + GtkWidget* proceed = find_button("ProceedButton"); + ezgl::press_proceed(proceed, &application); + + } else { + manual_moves_global.manual_move_info.valid_input = false; + } } bool string_is_a_number(std::string block_id) { - for (size_t i = 0; i < block_id.size(); i++) { - //Returns 0 if the string does not have characters from 0-9 - if (isdigit(block_id[i]) == 0) { - return false; - } - } - return true; + for (size_t i = 0; i < block_id.size(); i++) { + //Returns 0 if the string does not have characters from 0-9 + if (isdigit(block_id[i]) == 0) { + return false; + } + } + return true; } void get_manual_move_flag() { - GObject *manual_moves = application.get_object("manualMove"); - //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); - manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); - //return manual_moves_global.manual_move_flag; + GObject* manual_moves = application.get_object("manualMove"); + //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); + manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); + //return manual_moves_global.manual_move_flag; } ManualMovesGlobals* get_manual_moves_global() { - return &manual_moves_global; + return &manual_moves_global; } - //Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved &blocks_affected, float /*rlim*/) { - - int block_id = manual_moves_global.manual_move_info.blockID; - t_pl_loc to = manual_moves_global.manual_move_info.to_location; - ClusterBlockId b_from = ClusterBlockId(block_id); - - //Checking if the block was found - if (!b_from) { - return e_create_move::ABORT; //No movable block was found - } - - auto &place_ctx = g_vpr_ctx.placement(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &device_ctx = g_vpr_ctx.device(); - - //Gets the current location of the block to move. - t_pl_loc from = place_ctx.block_locs[b_from].loc; - auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); - auto grid_from_type = device_ctx.grid[from.x][from.y].type; - VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); - - //Retrieving the compressed block grid for this block type - const auto &compressed_block_grid = - place_ctx.compressed_block_grids[cluster_from_type->index]; - //Checking if the block has a compatible subtile. - auto to_type = device_ctx.grid[to.x][to.y].type; - auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); - - //No compatible subtile is found. - if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { - return e_create_move::ABORT; - } - - e_create_move create_move = ::create_move(blocks_affected, b_from, to); - return create_move; +e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/) { + int block_id = manual_moves_global.manual_move_info.blockID; + t_pl_loc to = manual_moves_global.manual_move_info.to_location; + ClusterBlockId b_from = ClusterBlockId(block_id); + + //Checking if the block was found + if (!b_from) { + return e_create_move::ABORT; //No movable block was found + } + + auto& place_ctx = g_vpr_ctx.placement(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& device_ctx = g_vpr_ctx.device(); + + //Gets the current location of the block to move. + t_pl_loc from = place_ctx.block_locs[b_from].loc; + auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); + auto grid_from_type = device_ctx.grid[from.x][from.y].type; + VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); + + //Retrieving the compressed block grid for this block type + const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; + //Checking if the block has a compatible subtile. + auto to_type = device_ctx.grid[to.x][to.y].type; + auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); + + //No compatible subtile is found. + if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { + return e_create_move::ABORT; + } + + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + return create_move; } void cost_summary_dialog() { - - GtkWidget *dialog; - GtkWidget *content_area; - - //Creating the dialog window - dialog = gtk_dialog_new_with_buttons("Move Costs", - (GtkWindow*)manual_moves_global.manual_move_window, - GTK_DIALOG_DESTROY_WITH_PARENT, - ("Accept"), - GTK_RESPONSE_ACCEPT, - ("Reject"), - GTK_RESPONSE_REJECT, - NULL); - - gtk_widget_set_halign(gtk_dialog_get_action_area((GtkDialog*) dialog), GTK_ALIGN_CENTER); - - //Create elements for the dialog and printing costs to the user. - GtkWidget *title_label = gtk_label_new(NULL); - gtk_label_set_markup((GtkLabel*) title_label, "Move Costs and Outcomes"); - std::string delta_cost = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost) + " "; - GtkWidget *delta_cost_label = gtk_label_new(delta_cost.c_str()); - std::string delta_timing = " Delta Timing: " + std::to_string(manual_moves_global.manual_move_info.delta_timing) + " "; - GtkWidget *delta_timing_label = gtk_label_new(delta_timing.c_str()); - std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box) + " "; - GtkWidget *delta_bounding_box_label = gtk_label_new(delta_bounding_box.c_str()); - std::string outcome = e_move_result_to_string(manual_moves_global.manual_move_info.placer_move_outcome); - std::string move_outcome = " Annealing Decision: " + outcome + " "; - GtkWidget *move_outcome_label = gtk_label_new(move_outcome.c_str()); - GtkWidget *space_label1 = gtk_label_new(" "); - GtkWidget *space_label2 = gtk_label_new(" "); - - //Attach elements to the content area of the dialog. - content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - gtk_container_add(GTK_CONTAINER(content_area), title_label); - gtk_container_add(GTK_CONTAINER(content_area), space_label1); - gtk_container_add(GTK_CONTAINER(content_area), delta_cost_label); - gtk_container_add(GTK_CONTAINER(content_area), delta_timing_label); - gtk_container_add(GTK_CONTAINER(content_area), delta_bounding_box_label); - gtk_container_add(GTK_CONTAINER(content_area), move_outcome_label); - gtk_container_add(GTK_CONTAINER(content_area), space_label2); - - //Show the dialog with all the labels. - gtk_widget_show_all(dialog); - - //Update message if user accepts the move. - std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); - msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; - - //Waiting for the user to respond to return to try_swa function. - int result = gtk_dialog_run(GTK_DIALOG(dialog)); - switch(result) { - - //If the user accepts the manual move - case GTK_RESPONSE_ACCEPT: - manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; - application.update_message(msg.c_str()); - break; - //If the user rejects the manual move - case GTK_RESPONSE_REJECT: - manual_moves_global.manual_move_info.user_move_outcome = REJECTED; - application.update_message("Manual move was rejected"); - break; - default: - manual_moves_global.manual_move_info.user_move_outcome = ABORTED; - break; - - } - - //Destroys the move outcome dialog. - gtk_widget_destroy(dialog); - + GtkWidget* dialog; + GtkWidget* content_area; + + //Creating the dialog window + dialog = gtk_dialog_new_with_buttons("Move Costs", + (GtkWindow*)manual_moves_global.manual_move_window, + GTK_DIALOG_DESTROY_WITH_PARENT, + ("Accept"), + GTK_RESPONSE_ACCEPT, + ("Reject"), + GTK_RESPONSE_REJECT, + NULL); + + gtk_widget_set_halign(gtk_dialog_get_action_area((GtkDialog*)dialog), GTK_ALIGN_CENTER); + + //Create elements for the dialog and printing costs to the user. + GtkWidget* title_label = gtk_label_new(NULL); + gtk_label_set_markup((GtkLabel*)title_label, "Move Costs and Outcomes"); + std::string delta_cost = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost) + " "; + GtkWidget* delta_cost_label = gtk_label_new(delta_cost.c_str()); + std::string delta_timing = " Delta Timing: " + std::to_string(manual_moves_global.manual_move_info.delta_timing) + " "; + GtkWidget* delta_timing_label = gtk_label_new(delta_timing.c_str()); + std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box) + " "; + GtkWidget* delta_bounding_box_label = gtk_label_new(delta_bounding_box.c_str()); + std::string outcome = e_move_result_to_string(manual_moves_global.manual_move_info.placer_move_outcome); + std::string move_outcome = " Annealing Decision: " + outcome + " "; + GtkWidget* move_outcome_label = gtk_label_new(move_outcome.c_str()); + GtkWidget* space_label1 = gtk_label_new(" "); + GtkWidget* space_label2 = gtk_label_new(" "); + + //Attach elements to the content area of the dialog. + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_container_add(GTK_CONTAINER(content_area), title_label); + gtk_container_add(GTK_CONTAINER(content_area), space_label1); + gtk_container_add(GTK_CONTAINER(content_area), delta_cost_label); + gtk_container_add(GTK_CONTAINER(content_area), delta_timing_label); + gtk_container_add(GTK_CONTAINER(content_area), delta_bounding_box_label); + gtk_container_add(GTK_CONTAINER(content_area), move_outcome_label); + gtk_container_add(GTK_CONTAINER(content_area), space_label2); + + //Show the dialog with all the labels. + gtk_widget_show_all(dialog); + + //Update message if user accepts the move. + std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); + msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; + + //Waiting for the user to respond to return to try_swa function. + int result = gtk_dialog_run(GTK_DIALOG(dialog)); + switch (result) { + //If the user accepts the manual move + case GTK_RESPONSE_ACCEPT: + manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + application.update_message(msg.c_str()); + break; + //If the user rejects the manual move + case GTK_RESPONSE_REJECT: + manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + application.update_message("Manual move was rejected"); + break; + default: + manual_moves_global.manual_move_info.user_move_outcome = ABORTED; + break; + } + + //Destroys the move outcome dialog. + gtk_widget_destroy(dialog); } void highlight_new_block_location(bool manual_move_flag) { - if(manual_move_flag) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - //Unselects all blocks first - deselect_all(); - //Highlighting the block - ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); - application.refresh_drawing(); - } + if (manual_move_flag) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + //Unselects all blocks first + deselect_all(); + //Highlighting the block + ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); + application.refresh_drawing(); + } } //Updates ManualMovesInfo cost members void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { - manual_moves_global.manual_move_info.delta_cost = d_cost; - manual_moves_global.manual_move_info.delta_timing = d_timing; - manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; - manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; + manual_moves_global.manual_move_info.delta_cost = d_cost; + manual_moves_global.manual_move_info.delta_timing = d_timing; + manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; + manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; } //Manual move window turns false, the window is destroyed. void close_manual_moves_window() { - manual_moves_global.mm_window_is_open = false; + manual_moves_global.mm_window_is_open = false; } //Deactivates the toggle button once the windows close. void deactivating_toggle_button() { - GObject *manual_move_toggle = application.get_object("manualMove"); - gtk_toggle_button_set_active((GtkToggleButton*) manual_move_toggle, FALSE); + GObject* manual_move_toggle = application.get_object("manualMove"); + gtk_toggle_button_set_active((GtkToggleButton*)manual_move_toggle, FALSE); } #endif diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 062707b80c5..1d6bf1d17fb 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -21,59 +21,59 @@ # include struct ManualMovesInfo { - int blockID = -1; - int x_pos = -1; - int y_pos = -1; - int subtile = 0; - double delta_cost = 0; - double delta_timing = 0; - double delta_bounding_box = 0; - bool valid_input = true; - t_pl_loc to_location; - e_move_result placer_move_outcome = ABORTED; - e_move_result user_move_outcome = ABORTED; + int blockID = -1; + int x_pos = -1; + int y_pos = -1; + int subtile = 0; + double delta_cost = 0; + double delta_timing = 0; + double delta_bounding_box = 0; + bool valid_input = true; + t_pl_loc to_location; + e_move_result placer_move_outcome = ABORTED; + e_move_result user_move_outcome = ABORTED; }; struct ManualMovesGlobals { - ManualMovesInfo manual_move_info; - GtkWidget* manual_move_window; - bool mm_window_is_open = false; - bool user_highlighted_block = false; - bool manual_move_flag = false; + ManualMovesInfo manual_move_info; + GtkWidget* manual_move_window; + bool mm_window_is_open = false; + bool user_highlighted_block = false; + bool manual_move_flag = false; }; /** Manual Moves Generator, inherits from MoveGenerator class **/ -class ManualMoveGenerator: public MoveGenerator { - public: - //Evaluates if move is successful and legal or unable to do. - e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/); +class ManualMoveGenerator : public MoveGenerator { + public: + //Evaluates if move is successful and legal or unable to do. + e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/); }; class Timer { - public: - Timer() { - m_StartTimepoint = std::chrono::high_resolution_clock::now(); - } - ~Timer() { - Stop(); - } - void Stop() { - auto endTimepoint = std::chrono::high_resolution_clock::now(); - - auto start = std::chrono::time_point_cast(m_StartTimepoint).time_since_epoch().count(); - auto end = std::chrono::time_point_cast(endTimepoint).time_since_epoch().count(); - - auto duration = end - start; - double ms = duration * 0.001; - double s = duration * 0.000001; - - std::cout << duration << "us -- " << ms << "ms -- " << s << "s\n"; - } - private: - std::chrono::time_point m_StartTimepoint; + public: + Timer() { + m_StartTimepoint = std::chrono::high_resolution_clock::now(); + } + ~Timer() { + Stop(); + } + void Stop() { + auto endTimepoint = std::chrono::high_resolution_clock::now(); + + auto start = std::chrono::time_point_cast(m_StartTimepoint).time_since_epoch().count(); + auto end = std::chrono::time_point_cast(endTimepoint).time_since_epoch().count(); + + auto duration = end - start; + double ms = duration * 0.001; + double s = duration * 0.000001; + + std::cout << duration << "us -- " << ms << "ms -- " << s << "s\n"; + } + + private: + std::chrono::time_point m_StartTimepoint; }; - /** manual moves functions **/ void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); @@ -88,8 +88,6 @@ void highlight_new_block_location(bool manual_move_flag); void deactivating_toggle_button(); - - #endif /*NO_GRAPHICS */ #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 8dbe4523aff..ecbdc38dd1f 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -452,13 +452,13 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& place_ctx = g_vpr_ctx.placement(); //For manual moves feature - ManualMovesGlobals *manual_move_global = get_manual_moves_global(); + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { - if(manual_move_global->manual_move_flag) { - invalid_breakpoint_entry_window("Dimensions are out of bounds"); - } + if (manual_move_global->manual_move_flag) { + invalid_breakpoint_entry_window("Dimensions are out of bounds"); + } return false; } @@ -467,18 +467,18 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { - if(manual_move_global->manual_move_flag) { - invalid_breakpoint_entry_window("Blocks are not compatible"); - } + if (manual_move_global->manual_move_flag) { + invalid_breakpoint_entry_window("Blocks are not compatible"); + } return false; } // If the destination block is user constrained, abort this swap auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { if (place_ctx.block_locs[b_to].is_fixed) { - if(manual_move_global->manual_move_flag) { - invalid_breakpoint_entry_window("Block is fixed"); - } + if (manual_move_global->manual_move_flag) { + invalid_breakpoint_entry_window("Block is fixed"); + } return false; } } @@ -860,6 +860,6 @@ bool find_compatible_compressed_loc_in_range(t_logical_block_type_ptr type, int } std::string e_move_result_to_string(e_move_result move_outcome) { - std::string move_result_to_string[] = {"Rejected", "Accepted", "Aborted"}; - return move_result_to_string[move_outcome]; + std::string move_result_to_string[] = {"Rejected", "Accepted", "Aborted"}; + return move_result_to_string[move_outcome]; } diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index 210799f2df3..1005b554a76 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -43,7 +43,6 @@ struct t_edge_cost { float criticality; //the timing criticality of the net terminal that caused this edge }; - /** * @brief Stores the bounding box of a net in terms of the minimum and * maximum coordinates of the blocks forming the net, clipped to diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index a195df0377e..70459ebc837 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -96,7 +96,8 @@ using std::min; */ enum e_cost_methods { - NORMAL, CHECK + NORMAL, + CHECK }; constexpr float INVALID_DELAY = std::numeric_limits::quiet_NaN(); @@ -129,8 +130,8 @@ static vtr::vector bb_updated_before; * number of tracks in that direction; for other cost functions they * * will never be used. * */ -static float **chanx_place_cost_fac; //[0...device_ctx.grid.width()-2] -static float **chany_place_cost_fac; //[0...device_ctx.grid.height()-2] +static float** chanx_place_cost_fac; //[0...device_ctx.grid.width()-2] +static float** chany_place_cost_fac; //[0...device_ctx.grid.height()-2] /* The following arrays are used by the try_swap function for speed. */ /* [0...cluster_ctx.clb_nlist.nets().size()-1] */ @@ -150,16 +151,16 @@ static int num_ts_called = 0; * Multiplied to bounding box of a net to better estimate wire length * * for higher fanout nets. Each entry is the correction factor for the * * fanout index-1 */ -static const float cross_count[50] = {/* [0..49] */1.0, 1.0, 1.0, 1.0828, - 1.1536, 1.2206, 1.2823, 1.3385, 1.3991, 1.4493, 1.4974, 1.5455, 1.5937, - 1.6418, 1.6899, 1.7304, 1.7709, 1.8114, 1.8519, 1.8924, 1.9288, 1.9652, - 2.0015, 2.0379, 2.0743, 2.1061, 2.1379, 2.1698, 2.2016, 2.2334, 2.2646, - 2.2958, 2.3271, 2.3583, 2.3895, 2.4187, 2.4479, 2.4772, 2.5064, 2.5356, - 2.5610, 2.5864, 2.6117, 2.6371, 2.6625, 2.6887, 2.7148, 2.7410, 2.7671, - 2.7933 }; +static const float cross_count[50] = {/* [0..49] */ 1.0, 1.0, 1.0, 1.0828, + 1.1536, 1.2206, 1.2823, 1.3385, 1.3991, 1.4493, 1.4974, 1.5455, 1.5937, + 1.6418, 1.6899, 1.7304, 1.7709, 1.8114, 1.8519, 1.8924, 1.9288, 1.9652, + 2.0015, 2.0379, 2.0743, 2.1061, 2.1379, 2.1698, 2.2016, 2.2334, 2.2646, + 2.2958, 2.3271, 2.3583, 2.3895, 2.4187, 2.4479, 2.4772, 2.5064, 2.5356, + 2.5610, 2.5864, 2.6117, 2.6371, 2.6625, 2.6887, 2.7148, 2.7410, 2.7671, + 2.7933}; std::unique_ptr f_move_stats_file(nullptr, - vtr::fclose); + vtr::fclose); #ifdef VTR_ENABLE_DEBUG_LOGGIING # define LOG_MOVE_STATS_HEADER() \ @@ -239,13 +240,14 @@ static void print_clb_placement(const char* fname); #endif static void alloc_and_load_placement_structs(float place_cost_exp, - const t_placer_opts &placer_opts, t_direct_inf *directs, - int num_directs); + const t_placer_opts& placer_opts, + t_direct_inf* directs, + int num_directs); static void alloc_and_load_try_swap_structs(); static void free_try_swap_structs(); -static void free_placement_structs(const t_placer_opts &placer_opts); +static void free_placement_structs(const t_placer_opts& placer_opts); static void alloc_and_load_for_fast_cost_update(float place_cost_exp); @@ -256,229 +258,249 @@ static double comp_bb_cost(e_cost_methods method); static void update_move_nets(int num_nets_affected); static void reset_move_nets(int num_nets_affected); -static e_move_result try_swap(const t_annealing_state *state, - t_placer_costs *costs, MoveGenerator &move_generator, - ManualMoveGenerator &manual_move_generator, - SetupTimingInfo *timing_info, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - t_pl_blocks_to_be_moved &blocks_affected, - const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, - PlacerSetupSlacks *setup_slacks, const t_placer_opts &placer_opts, - MoveTypeStat &move_type_stat, const t_place_algorithm &place_algorithm, - float timing_bb_factor); - -static void check_place(const t_placer_costs &costs, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, - const t_place_algorithm &place_algorithm); - -static int check_placement_costs(const t_placer_costs &costs, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, - const t_place_algorithm &place_algorithm); +static e_move_result try_swap(const t_annealing_state* state, + t_placer_costs* costs, + MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, + SetupTimingInfo* timing_info, + ClusteredPinTimingInvalidator* pin_timing_invalidator, + t_pl_blocks_to_be_moved& blocks_affected, + const PlaceDelayModel* delay_model, + PlacerCriticalities* criticalities, + PlacerSetupSlacks* setup_slacks, + const t_placer_opts& placer_opts, + MoveTypeStat& move_type_stat, + const t_place_algorithm& place_algorithm, + float timing_bb_factor); + +static void check_place(const t_placer_costs& costs, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + const t_place_algorithm& place_algorithm); + +static int check_placement_costs(const t_placer_costs& costs, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + const t_place_algorithm& place_algorithm); static int check_placement_consistency(); static int check_block_placement_consistency(); static int check_macro_placement_consistency(); -static float starting_t(const t_annealing_state *state, t_placer_costs *costs, - t_annealing_sched annealing_sched, const PlaceDelayModel *delay_model, - PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, - SetupTimingInfo *timing_info, MoveGenerator &move_generator, - ManualMoveGenerator &manual_move_generator, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - t_pl_blocks_to_be_moved &blocks_affected, - const t_placer_opts &placer_opts, MoveTypeStat &move_type_stat); +static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t_annealing_sched annealing_sched, const PlaceDelayModel* delay_model, PlacerCriticalities* criticalities, PlacerSetupSlacks* setup_slacks, SetupTimingInfo* timing_info, MoveGenerator& move_generator, ManualMoveGenerator& manual_move_generator, ClusteredPinTimingInvalidator* pin_timing_invalidator, t_pl_blocks_to_be_moved& blocks_affected, const t_placer_opts& placer_opts, MoveTypeStat& move_type_stat); static int count_connections(); static double recompute_bb_cost(); -static void commit_td_cost(const t_pl_blocks_to_be_moved &blocks_affected); +static void commit_td_cost(const t_pl_blocks_to_be_moved& blocks_affected); -static void revert_td_cost(const t_pl_blocks_to_be_moved &blocks_affected); +static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected); static void invalidate_affected_connections( - const t_pl_blocks_to_be_moved &blocks_affected, - ClusteredPinTimingInvalidator *pin_tedges_invalidator, - TimingInfo *timing_info); + const t_pl_blocks_to_be_moved& blocks_affected, + ClusteredPinTimingInvalidator* pin_tedges_invalidator, + TimingInfo* timing_info); static bool driven_by_moved_block(const ClusterNetId net, - const t_pl_blocks_to_be_moved &blocks_affected); + const t_pl_blocks_to_be_moved& blocks_affected); -static float analyze_setup_slack_cost(const PlacerSetupSlacks *setup_slacks); +static float analyze_setup_slack_cost(const PlacerSetupSlacks* setup_slacks); static e_move_result assess_swap(double delta_c, double t); -static void get_non_updateable_bb(ClusterNetId net_id, t_bb *bb_coord_new); +static void get_non_updateable_bb(ClusterNetId net_id, t_bb* bb_coord_new); -static void update_bb(ClusterNetId net_id, t_bb *bb_coord_new, - t_bb *bb_edge_new, int xold, int yold, int xnew, int ynew); +static void update_bb(ClusterNetId net_id, t_bb* bb_coord_new, t_bb* bb_edge_new, int xold, int yold, int xnew, int ynew); static int find_affected_nets_and_update_costs( - const t_place_algorithm &place_algorithm, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, - t_pl_blocks_to_be_moved &blocks_affected, double &bb_delta_c, - double &timing_delta_c); + const t_place_algorithm& place_algorithm, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + t_pl_blocks_to_be_moved& blocks_affected, + double& bb_delta_c, + double& timing_delta_c); -static void record_affected_net(const ClusterNetId net, int &num_affected_nets); +static void record_affected_net(const ClusterNetId net, int& num_affected_nets); static void update_net_bb(const ClusterNetId net, - const t_pl_blocks_to_be_moved &blocks_affected, int iblk, - const ClusterBlockId blk, const ClusterPinId blk_pin); -static void update_td_delta_costs(const PlaceDelayModel *delay_model, - const PlacerCriticalities &criticalities, const ClusterNetId net, - const ClusterPinId pin, t_pl_blocks_to_be_moved &blocks_affected, - double &delta_timing_cost); + const t_pl_blocks_to_be_moved& blocks_affected, + int iblk, + const ClusterBlockId blk, + const ClusterPinId blk_pin); +static void update_td_delta_costs(const PlaceDelayModel* delay_model, + const PlacerCriticalities& criticalities, + const ClusterNetId net, + const ClusterPinId pin, + t_pl_blocks_to_be_moved& blocks_affected, + double& delta_timing_cost); -static double get_net_cost(ClusterNetId net_id, t_bb *bb_ptr); +static double get_net_cost(ClusterNetId net_id, t_bb* bb_ptr); -static void get_bb_from_scratch(ClusterNetId net_id, t_bb *coords, - t_bb *num_on_edges); +static void get_bb_from_scratch(ClusterNetId net_id, t_bb* coords, t_bb* num_on_edges); -static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb *bbptr); +static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb* bbptr); static void free_try_swap_arrays(); -static void outer_loop_update_timing_info(const t_placer_opts &placer_opts, - t_placer_costs *costs, int num_connections, float crit_exponent, - int *outer_crit_iter_count, const PlaceDelayModel *delay_model, - PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - SetupTimingInfo *timing_info); - -static void placement_inner_loop(const t_annealing_state *state, - const t_placer_opts &placer_opts, int inner_recompute_limit, - t_placer_statistics *stats, t_placer_costs *costs, - int *moves_since_cost_recompute, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, - PlacerSetupSlacks *setup_slacks, MoveGenerator &move_generator, - ManualMoveGenerator &manual_move_generator, - t_pl_blocks_to_be_moved &blocks_affected, SetupTimingInfo *timing_info, - const t_place_algorithm &place_algorithm, MoveTypeStat &move_type_stat, - float timing_bb_factor); - -static void recompute_costs_from_scratch(const t_placer_opts &placer_opts, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, t_placer_costs *costs); - -static void generate_post_place_timing_reports(const t_placer_opts &placer_opts, - const t_analysis_opts &analysis_opts, - const SetupTimingInfo &timing_info, - const PlacementDelayCalculator &delay_calc); +static void outer_loop_update_timing_info(const t_placer_opts& placer_opts, + t_placer_costs* costs, + int num_connections, + float crit_exponent, + int* outer_crit_iter_count, + const PlaceDelayModel* delay_model, + PlacerCriticalities* criticalities, + PlacerSetupSlacks* setup_slacks, + ClusteredPinTimingInvalidator* pin_timing_invalidator, + SetupTimingInfo* timing_info); + +static void placement_inner_loop(const t_annealing_state* state, + const t_placer_opts& placer_opts, + int inner_recompute_limit, + t_placer_statistics* stats, + t_placer_costs* costs, + int* moves_since_cost_recompute, + ClusteredPinTimingInvalidator* pin_timing_invalidator, + const PlaceDelayModel* delay_model, + PlacerCriticalities* criticalities, + PlacerSetupSlacks* setup_slacks, + MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, + t_pl_blocks_to_be_moved& blocks_affected, + SetupTimingInfo* timing_info, + const t_place_algorithm& place_algorithm, + MoveTypeStat& move_type_stat, + float timing_bb_factor); + +static void recompute_costs_from_scratch(const t_placer_opts& placer_opts, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + t_placer_costs* costs); + +static void generate_post_place_timing_reports(const t_placer_opts& placer_opts, + const t_analysis_opts& analysis_opts, + const SetupTimingInfo& timing_info, + const PlacementDelayCalculator& delay_calc); //calculate the agent's reward and the total process outcome static void calculate_reward_and_process_outcome( - const t_placer_opts &placer_opts, - const MoveOutcomeStats &move_outcome_stats, const double &delta_c, - float timing_bb_factor, MoveGenerator &move_generator); + const t_placer_opts& placer_opts, + const MoveOutcomeStats& move_outcome_stats, + const double& delta_c, + float timing_bb_factor, + MoveGenerator& move_generator); static void print_place_status_header(); -static void print_place_status(const t_annealing_state &state, - const t_placer_statistics &stats, float elapsed_sec, float cpd, - float sTNS, float sWNS, size_t tot_moves); +static void print_place_status(const t_annealing_state& state, + const t_placer_statistics& stats, + float elapsed_sec, + float cpd, + float sTNS, + float sWNS, + size_t tot_moves); static void print_resources_utilization(); -static void print_placement_swaps_stats(const t_annealing_state &state); +static void print_placement_swaps_stats(const t_annealing_state& state); static void print_placement_move_types_stats( - const MoveTypeStat &move_type_stat); + const MoveTypeStat& move_type_stat); /*****************************************************************************/ -void try_place(const t_placer_opts &placer_opts, - t_annealing_sched annealing_sched, const t_router_opts &router_opts, - const t_analysis_opts &analysis_opts, t_chan_width_dist chan_width_dist, - t_det_routing_arch *det_routing_arch, - std::vector &segment_inf, t_direct_inf *directs, - int num_directs) { - /* Does almost all the work of placing a circuit. Width_fac gives the * - * width of the widest channel. Place_cost_exp says what exponent the * - * width should be taken to when calculating costs. This allows a * - * greater bias for anisotropic architectures. */ - auto &device_ctx = g_vpr_ctx.device(); - auto &atom_ctx = g_vpr_ctx.atom(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_move_ctx = g_placer_ctx.mutable_move(); - - const auto &p_timing_ctx = g_placer_ctx.timing(); - const auto &p_runtime_ctx = g_placer_ctx.runtime(); - - auto &timing_ctx = g_vpr_ctx.timing(); - auto pre_place_timing_stats = timing_ctx.stats; - int tot_iter, moves_since_cost_recompute, width_fac, num_connections, - outer_crit_iter_count, inner_recompute_limit; - float first_crit_exponent, first_rlim, first_t; - int first_move_lim; - - t_placer_costs costs(placer_opts.place_algorithm); - - tatum::TimingPathInfo critical_path; - float sTNS = NAN; - float sWNS = NAN; - - char msg[vtr::bufsize]; - t_placer_statistics stats; - - t_placement_checkpoint placement_checkpoint; - - std::shared_ptr timing_info; - std::shared_ptr placement_delay_calc; - std::unique_ptr place_delay_model; - std::unique_ptr move_generator; - std::unique_ptr move_generator2; - std::unique_ptr manual_move_generator; - std::unique_ptr placer_setup_slacks; - - std::unique_ptr placer_criticalities; - std::unique_ptr pin_timing_invalidator; - - t_pl_blocks_to_be_moved blocks_affected( - cluster_ctx.clb_nlist.blocks().size()); - - /* Allocated here because it goes into timing critical code where each memory allocation is expensive */ - IntraLbPbPinLookup pb_gpin_lookup(device_ctx.logical_block_types); - - /* init file scope variables */ - num_swap_rejected = 0; - num_swap_accepted = 0; - num_swap_aborted = 0; - num_ts_called = 0; - - if (placer_opts.place_algorithm.is_timing_driven()) { - /*do this before the initial placement to avoid messing up the initial placement */ - place_delay_model = alloc_lookups_and_delay_model(chan_width_dist, - placer_opts, router_opts, det_routing_arch, segment_inf, - directs, num_directs); - - if (isEchoFileEnabled(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)) { - place_delay_model->dump_echo( - getEchoFileName(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)); - } - } - - int move_lim = 1; - move_lim = (int) (annealing_sched.inner_num - * pow(cluster_ctx.clb_nlist.blocks().size(), 1.3333)); - - //create the move generator based on the chosen strategy - create_move_generators(move_generator, move_generator2, placer_opts, - move_lim); - - width_fac = placer_opts.place_chan_width; - - init_chan(width_fac, chan_width_dist); - - alloc_and_load_placement_structs(placer_opts.place_cost_exp, placer_opts, - directs, num_directs); - - vtr::ScopedStartFinishTimer timer("Placement"); - - initial_placement(placer_opts.pad_loc_type, - placer_opts.constraints_file.c_str()); +void try_place(const t_placer_opts& placer_opts, + t_annealing_sched annealing_sched, + const t_router_opts& router_opts, + const t_analysis_opts& analysis_opts, + t_chan_width_dist chan_width_dist, + t_det_routing_arch* det_routing_arch, + std::vector& segment_inf, + t_direct_inf* directs, + int num_directs) { + /* Does almost all the work of placing a circuit. Width_fac gives the * + * width of the widest channel. Place_cost_exp says what exponent the * + * width should be taken to when calculating costs. This allows a * + * greater bias for anisotropic architectures. */ + auto& device_ctx = g_vpr_ctx.device(); + auto& atom_ctx = g_vpr_ctx.atom(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_move_ctx = g_placer_ctx.mutable_move(); + + const auto& p_timing_ctx = g_placer_ctx.timing(); + const auto& p_runtime_ctx = g_placer_ctx.runtime(); + + auto& timing_ctx = g_vpr_ctx.timing(); + auto pre_place_timing_stats = timing_ctx.stats; + int tot_iter, moves_since_cost_recompute, width_fac, num_connections, + outer_crit_iter_count, inner_recompute_limit; + float first_crit_exponent, first_rlim, first_t; + int first_move_lim; + + t_placer_costs costs(placer_opts.place_algorithm); + + tatum::TimingPathInfo critical_path; + float sTNS = NAN; + float sWNS = NAN; + + char msg[vtr::bufsize]; + t_placer_statistics stats; + + t_placement_checkpoint placement_checkpoint; + + std::shared_ptr timing_info; + std::shared_ptr placement_delay_calc; + std::unique_ptr place_delay_model; + std::unique_ptr move_generator; + std::unique_ptr move_generator2; + std::unique_ptr manual_move_generator; + std::unique_ptr placer_setup_slacks; + + std::unique_ptr placer_criticalities; + std::unique_ptr pin_timing_invalidator; + + t_pl_blocks_to_be_moved blocks_affected( + cluster_ctx.clb_nlist.blocks().size()); + + /* Allocated here because it goes into timing critical code where each memory allocation is expensive */ + IntraLbPbPinLookup pb_gpin_lookup(device_ctx.logical_block_types); + + /* init file scope variables */ + num_swap_rejected = 0; + num_swap_accepted = 0; + num_swap_aborted = 0; + num_ts_called = 0; + + if (placer_opts.place_algorithm.is_timing_driven()) { + /*do this before the initial placement to avoid messing up the initial placement */ + place_delay_model = alloc_lookups_and_delay_model(chan_width_dist, + placer_opts, router_opts, det_routing_arch, segment_inf, + directs, num_directs); + + if (isEchoFileEnabled(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)) { + place_delay_model->dump_echo( + getEchoFileName(E_ECHO_PLACEMENT_DELTA_DELAY_MODEL)); + } + } + + int move_lim = 1; + move_lim = (int)(annealing_sched.inner_num + * pow(cluster_ctx.clb_nlist.blocks().size(), 1.3333)); + + //create the move generator based on the chosen strategy + create_move_generators(move_generator, move_generator2, placer_opts, + move_lim); + + width_fac = placer_opts.place_chan_width; + + init_chan(width_fac, chan_width_dist); + + alloc_and_load_placement_structs(placer_opts.place_cost_exp, placer_opts, + directs, num_directs); + + vtr::ScopedStartFinishTimer timer("Placement"); + + initial_placement(placer_opts.pad_loc_type, + placer_opts.constraints_file.c_str()); #ifdef ENABLE_ANALYTIC_PLACE /* @@ -492,218 +514,218 @@ void try_place(const t_placer_opts &placer_opts, } #endif /* ENABLE_ANALYTIC_PLACE */ - // Update physical pin values - for (auto block_id : cluster_ctx.clb_nlist.blocks()) { - place_sync_external_block_connections(block_id); - } - - init_draw_coords((float) width_fac); - //Enables fast look-up of atom pins connect to CLB pins - ClusteredPinAtomPinsLookup netlist_pin_lookup(cluster_ctx.clb_nlist, - atom_ctx.nlist, pb_gpin_lookup); - - /* Gets initial cost and loads bounding boxes. */ - - if (placer_opts.place_algorithm.is_timing_driven()) { - costs.bb_cost = comp_bb_cost(NORMAL); - - first_crit_exponent = placer_opts.td_place_exp_first; /*this will be modified when rlim starts to change */ - - num_connections = count_connections(); - VTR_LOG("\n"); - VTR_LOG("There are %d point to point connections in this circuit.\n", - num_connections); - VTR_LOG("\n"); - - //Update the point-to-point delays from the initial placement - comp_td_connection_delays(place_delay_model.get()); - - /* - * Initialize timing analysis - */ - placement_delay_calc = std::make_shared( - atom_ctx.nlist, atom_ctx.lookup, p_timing_ctx.connection_delay); - placement_delay_calc->set_tsu_margin_relative( - placer_opts.tsu_rel_margin); - placement_delay_calc->set_tsu_margin_absolute( - placer_opts.tsu_abs_margin); - - timing_info = make_setup_timing_info(placement_delay_calc, - placer_opts.timing_update_type); - - placer_setup_slacks = std::make_unique( - cluster_ctx.clb_nlist, netlist_pin_lookup); - - placer_criticalities = std::make_unique( - cluster_ctx.clb_nlist, netlist_pin_lookup); - - pin_timing_invalidator = - std::make_unique( - cluster_ctx.clb_nlist, netlist_pin_lookup, - atom_ctx.nlist, atom_ctx.lookup, - *timing_info->timing_graph()); - //First time compute timing and costs, compute from scratch - PlaceCritParams crit_params; - crit_params.crit_exponent = first_crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - initialize_timing_info(crit_params, place_delay_model.get(), - placer_criticalities.get(), placer_setup_slacks.get(), - pin_timing_invalidator.get(), timing_info.get(), &costs); - - critical_path = timing_info->least_slack_critical_path(); - - /* Write out the initial timing echo file */ - if (isEchoFileEnabled(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH)) { - tatum::write_echo( - getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH), - *timing_ctx.graph, *timing_ctx.constraints, - *placement_delay_calc, timing_info->analyzer()); - - tatum::NodeId debug_tnode = id_or_pin_name_to_tnode( - analysis_opts.echo_dot_timing_graph_node); - write_setup_timing_graph_dot( - getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH) - + std::string(".dot"), *timing_info, debug_tnode); - } - - outer_crit_iter_count = 1; - - /* Initialize the normalization factors. Calling costs.update_norm_factors() * - * here would fail the golden results of strong_sdc benchmark */ - costs.timing_cost_norm = 1 / costs.timing_cost; - costs.bb_cost_norm = 1 / costs.bb_cost; - costs.cost = 1; - } else { - VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); - - /* Total cost is the same as wirelength cost */ - costs.bb_cost = comp_bb_cost(NORMAL); - costs.cost = costs.bb_cost; - - /* Timing cost and normalization factors are not used */ - costs.timing_cost = INVALID_COST; - costs.timing_cost_norm = INVALID_COST; - costs.bb_cost_norm = INVALID_COST; - - /* Other initializations */ - outer_crit_iter_count = 0; - num_connections = 0; - first_crit_exponent = 0; - } - - //Sanity check that initial placement is legal - check_place(costs, place_delay_model.get(), placer_criticalities.get(), - placer_opts.place_algorithm); - - //Initial pacement statistics - VTR_LOG("Initial placement cost: %g bb_cost: %g td_cost: %g\n", costs.cost, - costs.bb_cost, costs.timing_cost); - if (placer_opts.place_algorithm.is_timing_driven()) { - VTR_LOG( - "Initial placement estimated Critical Path Delay (CPD): %g ns\n", - 1e9 * critical_path.delay()); - VTR_LOG( - "Initial placement estimated setup Total Negative Slack (sTNS): %g ns\n", - 1e9 * timing_info->setup_total_negative_slack()); - VTR_LOG( - "Initial placement estimated setup Worst Negative Slack (sWNS): %g ns\n", - 1e9 * timing_info->setup_worst_negative_slack()); - VTR_LOG("\n"); - - VTR_LOG("Initial placement estimated setup slack histogram:\n"); - print_histogram( - create_setup_slack_histogram(*timing_info->setup_analyzer())); - } - size_t num_macro_members = 0; - for (auto ¯o : g_vpr_ctx.placement().pl_macros) { - num_macro_members += macro.members.size(); - } - VTR_LOG( - "Placement contains %zu placement macros involving %zu blocks (average macro size %f)\n", - g_vpr_ctx.placement().pl_macros.size(), num_macro_members, - float(num_macro_members) / g_vpr_ctx.placement().pl_macros.size()); - VTR_LOG("\n"); - - sprintf(msg, - "Initial Placement. Cost: %g BB Cost: %g TD Cost %g \t Channel Factor: %d", - costs.cost, costs.bb_cost, costs.timing_cost, width_fac); - //Draw the initial placement - update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); - - if (placer_opts.placement_saves_per_temperature >= 1) { - std::string filename = vtr::string_fmt("placement_%03d_%03d.place", 0, - 0); - VTR_LOG("Saving initial placement to file: %s\n", filename.c_str()); - print_place(nullptr, nullptr, filename.c_str()); - } - - first_move_lim = get_initial_move_lim(placer_opts, annealing_sched); - - if (placer_opts.inner_loop_recompute_divider != 0) { - inner_recompute_limit = (int) (0.5 - + (float) first_move_lim - / (float) placer_opts.inner_loop_recompute_divider); - } else { - /*don't do an inner recompute */ - inner_recompute_limit = first_move_lim + 1; - } - - /* calculate the number of moves in the quench that we should recompute timing after based on the value of * - * the commandline option quench_recompute_divider */ - int quench_recompute_limit; - if (placer_opts.quench_recompute_divider != 0) { - quench_recompute_limit = (int) (0.5 - + (float) move_lim - / (float) placer_opts.quench_recompute_divider); - } else { - /*don't do an quench recompute */ - quench_recompute_limit = first_move_lim + 1; - } - - //allocate helper vectors that are used by many move generators - place_move_ctx.X_coord.resize(10, 0); - place_move_ctx.Y_coord.resize(10, 0); - - //allocate move type statistics vectors - MoveTypeStat move_type_stat; - move_type_stat.num_moves.resize(placer_opts.place_static_move_prob.size(), - 0); - move_type_stat.accepted_moves.resize( - placer_opts.place_static_move_prob.size(), 0); - move_type_stat.aborted_moves.resize( - placer_opts.place_static_move_prob.size(), 0); - - /* Get the first range limiter */ - first_rlim = (float) max(device_ctx.grid.width() - 1, - device_ctx.grid.height() - 1); - place_move_ctx.first_rlim = first_rlim; - - /* Set the temperature high so essentially all swaps will be accepted */ - /* when trying to determine the starting temp for placement inner loop. */ - first_t = HUGE_POSITIVE_FLOAT; - - t_annealing_state state(annealing_sched, first_t, first_rlim, - first_move_lim, first_crit_exponent); - - /* Update the starting temperature for placement annealing to a more appropriate value */ - state.t = starting_t(&state, &costs, annealing_sched, - place_delay_model.get(), placer_criticalities.get(), - placer_setup_slacks.get(), timing_info.get(), *move_generator, - *manual_move_generator, pin_timing_invalidator.get(), - blocks_affected, placer_opts, move_type_stat); - - if (!placer_opts.move_stats_file.empty()) { - f_move_stats_file = std::unique_ptr( - vtr::fopen(placer_opts.move_stats_file.c_str(), "w"), - vtr::fclose); - LOG_MOVE_STATS_HEADER(); - } - - tot_iter = 0; - moves_since_cost_recompute = 0; - - bool skip_anneal = false; + // Update physical pin values + for (auto block_id : cluster_ctx.clb_nlist.blocks()) { + place_sync_external_block_connections(block_id); + } + + init_draw_coords((float)width_fac); + //Enables fast look-up of atom pins connect to CLB pins + ClusteredPinAtomPinsLookup netlist_pin_lookup(cluster_ctx.clb_nlist, + atom_ctx.nlist, pb_gpin_lookup); + + /* Gets initial cost and loads bounding boxes. */ + + if (placer_opts.place_algorithm.is_timing_driven()) { + costs.bb_cost = comp_bb_cost(NORMAL); + + first_crit_exponent = placer_opts.td_place_exp_first; /*this will be modified when rlim starts to change */ + + num_connections = count_connections(); + VTR_LOG("\n"); + VTR_LOG("There are %d point to point connections in this circuit.\n", + num_connections); + VTR_LOG("\n"); + + //Update the point-to-point delays from the initial placement + comp_td_connection_delays(place_delay_model.get()); + + /* + * Initialize timing analysis + */ + placement_delay_calc = std::make_shared( + atom_ctx.nlist, atom_ctx.lookup, p_timing_ctx.connection_delay); + placement_delay_calc->set_tsu_margin_relative( + placer_opts.tsu_rel_margin); + placement_delay_calc->set_tsu_margin_absolute( + placer_opts.tsu_abs_margin); + + timing_info = make_setup_timing_info(placement_delay_calc, + placer_opts.timing_update_type); + + placer_setup_slacks = std::make_unique( + cluster_ctx.clb_nlist, netlist_pin_lookup); + + placer_criticalities = std::make_unique( + cluster_ctx.clb_nlist, netlist_pin_lookup); + + pin_timing_invalidator = std::make_unique( + cluster_ctx.clb_nlist, netlist_pin_lookup, + atom_ctx.nlist, atom_ctx.lookup, + *timing_info->timing_graph()); + //First time compute timing and costs, compute from scratch + PlaceCritParams crit_params; + crit_params.crit_exponent = first_crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + initialize_timing_info(crit_params, place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + pin_timing_invalidator.get(), timing_info.get(), &costs); + + critical_path = timing_info->least_slack_critical_path(); + + /* Write out the initial timing echo file */ + if (isEchoFileEnabled(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH)) { + tatum::write_echo( + getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH), + *timing_ctx.graph, *timing_ctx.constraints, + *placement_delay_calc, timing_info->analyzer()); + + tatum::NodeId debug_tnode = id_or_pin_name_to_tnode( + analysis_opts.echo_dot_timing_graph_node); + write_setup_timing_graph_dot( + getEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH) + + std::string(".dot"), + *timing_info, debug_tnode); + } + + outer_crit_iter_count = 1; + + /* Initialize the normalization factors. Calling costs.update_norm_factors() * + * here would fail the golden results of strong_sdc benchmark */ + costs.timing_cost_norm = 1 / costs.timing_cost; + costs.bb_cost_norm = 1 / costs.bb_cost; + costs.cost = 1; + } else { + VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); + + /* Total cost is the same as wirelength cost */ + costs.bb_cost = comp_bb_cost(NORMAL); + costs.cost = costs.bb_cost; + + /* Timing cost and normalization factors are not used */ + costs.timing_cost = INVALID_COST; + costs.timing_cost_norm = INVALID_COST; + costs.bb_cost_norm = INVALID_COST; + + /* Other initializations */ + outer_crit_iter_count = 0; + num_connections = 0; + first_crit_exponent = 0; + } + + //Sanity check that initial placement is legal + check_place(costs, place_delay_model.get(), placer_criticalities.get(), + placer_opts.place_algorithm); + + //Initial pacement statistics + VTR_LOG("Initial placement cost: %g bb_cost: %g td_cost: %g\n", costs.cost, + costs.bb_cost, costs.timing_cost); + if (placer_opts.place_algorithm.is_timing_driven()) { + VTR_LOG( + "Initial placement estimated Critical Path Delay (CPD): %g ns\n", + 1e9 * critical_path.delay()); + VTR_LOG( + "Initial placement estimated setup Total Negative Slack (sTNS): %g ns\n", + 1e9 * timing_info->setup_total_negative_slack()); + VTR_LOG( + "Initial placement estimated setup Worst Negative Slack (sWNS): %g ns\n", + 1e9 * timing_info->setup_worst_negative_slack()); + VTR_LOG("\n"); + + VTR_LOG("Initial placement estimated setup slack histogram:\n"); + print_histogram( + create_setup_slack_histogram(*timing_info->setup_analyzer())); + } + size_t num_macro_members = 0; + for (auto& macro : g_vpr_ctx.placement().pl_macros) { + num_macro_members += macro.members.size(); + } + VTR_LOG( + "Placement contains %zu placement macros involving %zu blocks (average macro size %f)\n", + g_vpr_ctx.placement().pl_macros.size(), num_macro_members, + float(num_macro_members) / g_vpr_ctx.placement().pl_macros.size()); + VTR_LOG("\n"); + + sprintf(msg, + "Initial Placement. Cost: %g BB Cost: %g TD Cost %g \t Channel Factor: %d", + costs.cost, costs.bb_cost, costs.timing_cost, width_fac); + //Draw the initial placement + update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); + + if (placer_opts.placement_saves_per_temperature >= 1) { + std::string filename = vtr::string_fmt("placement_%03d_%03d.place", 0, + 0); + VTR_LOG("Saving initial placement to file: %s\n", filename.c_str()); + print_place(nullptr, nullptr, filename.c_str()); + } + + first_move_lim = get_initial_move_lim(placer_opts, annealing_sched); + + if (placer_opts.inner_loop_recompute_divider != 0) { + inner_recompute_limit = (int)(0.5 + + (float)first_move_lim + / (float)placer_opts.inner_loop_recompute_divider); + } else { + /*don't do an inner recompute */ + inner_recompute_limit = first_move_lim + 1; + } + + /* calculate the number of moves in the quench that we should recompute timing after based on the value of * + * the commandline option quench_recompute_divider */ + int quench_recompute_limit; + if (placer_opts.quench_recompute_divider != 0) { + quench_recompute_limit = (int)(0.5 + + (float)move_lim + / (float)placer_opts.quench_recompute_divider); + } else { + /*don't do an quench recompute */ + quench_recompute_limit = first_move_lim + 1; + } + + //allocate helper vectors that are used by many move generators + place_move_ctx.X_coord.resize(10, 0); + place_move_ctx.Y_coord.resize(10, 0); + + //allocate move type statistics vectors + MoveTypeStat move_type_stat; + move_type_stat.num_moves.resize(placer_opts.place_static_move_prob.size(), + 0); + move_type_stat.accepted_moves.resize( + placer_opts.place_static_move_prob.size(), 0); + move_type_stat.aborted_moves.resize( + placer_opts.place_static_move_prob.size(), 0); + + /* Get the first range limiter */ + first_rlim = (float)max(device_ctx.grid.width() - 1, + device_ctx.grid.height() - 1); + place_move_ctx.first_rlim = first_rlim; + + /* Set the temperature high so essentially all swaps will be accepted */ + /* when trying to determine the starting temp for placement inner loop. */ + first_t = HUGE_POSITIVE_FLOAT; + + t_annealing_state state(annealing_sched, first_t, first_rlim, + first_move_lim, first_crit_exponent); + + /* Update the starting temperature for placement annealing to a more appropriate value */ + state.t = starting_t(&state, &costs, annealing_sched, + place_delay_model.get(), placer_criticalities.get(), + placer_setup_slacks.get(), timing_info.get(), *move_generator, + *manual_move_generator, pin_timing_invalidator.get(), + blocks_affected, placer_opts, move_type_stat); + + if (!placer_opts.move_stats_file.empty()) { + f_move_stats_file = std::unique_ptr( + vtr::fopen(placer_opts.move_stats_file.c_str(), "w"), + vtr::fclose); + LOG_MOVE_STATS_HEADER(); + } + + tot_iter = 0; + moves_since_cost_recompute = 0; + + bool skip_anneal = false; #ifdef ENABLE_ANALYTIC_PLACE // Analytic placer: When enabled, skip most of the annealing and go straight to quench @@ -712,166 +734,166 @@ void try_place(const t_placer_opts &placer_opts, skip_anneal = true; #endif /* ENABLE_ANALYTIC_PLACE */ - //RL agent state definition - e_agent_state agent_state = EARLY_IN_THE_ANNEAL; - - std::unique_ptr current_move_generator; - - //Define the timing bb weight factor for the agent's reward function - float timing_bb_factor = REWARD_BB_TIMING_RELATIVE_WEIGHT; - - if (skip_anneal == false) { - //Table header - VTR_LOG("\n"); - print_place_status_header(); - - /* Outer loop of the simulated annealing begins */ - do { - vtr::Timer temperature_timer; - - outer_loop_update_timing_info(placer_opts, &costs, num_connections, - state.crit_exponent, &outer_crit_iter_count, - place_delay_model.get(), placer_criticalities.get(), - placer_setup_slacks.get(), pin_timing_invalidator.get(), - timing_info.get()); - - if (placer_opts.place_algorithm.is_timing_driven()) { - critical_path = timing_info->least_slack_critical_path(); - sTNS = timing_info->setup_total_negative_slack(); - sWNS = timing_info->setup_worst_negative_slack(); - - //see if we should save the current placement solution as a checkpoint - - if (placer_opts.place_checkpointing - && agent_state == LATE_IN_THE_ANNEAL) { - save_placement_checkpoint_if_needed(placement_checkpoint, - timing_info, costs, critical_path.delay()); - } - } - - //move the appropoiate move_generator to be the current used move generator - assign_current_move_generator(move_generator, move_generator2, - agent_state, placer_opts, false, current_move_generator); - - //do a complete inner loop iteration - placement_inner_loop(&state, placer_opts, inner_recompute_limit, - &stats, &costs, &moves_since_cost_recompute, - pin_timing_invalidator.get(), place_delay_model.get(), - placer_criticalities.get(), placer_setup_slacks.get(), - *current_move_generator, *manual_move_generator, - blocks_affected, timing_info.get(), - placer_opts.place_algorithm, move_type_stat, - timing_bb_factor); - - //move the update used move_generator to its original variable - update_move_generator(move_generator, move_generator2, agent_state, - placer_opts, false, current_move_generator); - - tot_iter += state.move_lim; - ++state.num_temps; - - print_place_status(state, stats, temperature_timer.elapsed_sec(), - critical_path.delay(), sTNS, sWNS, tot_iter); - if (placer_opts.place_algorithm.is_timing_driven() - && placer_opts.place_agent_multistate - && agent_state == EARLY_IN_THE_ANNEAL) { - if (state.alpha < 0.85 && state.alpha > 0.6) { - agent_state = LATE_IN_THE_ANNEAL; - VTR_LOG("Agent's 2nd state: \n"); - } - } - - sprintf(msg, "Cost: %g BB Cost %g TD Cost %g Temperature: %g", - costs.cost, costs.bb_cost, costs.timing_cost, state.t); - update_screen(ScreenUpdatePriority::MINOR, msg, PLACEMENT, - timing_info); + //RL agent state definition + e_agent_state agent_state = EARLY_IN_THE_ANNEAL; + + std::unique_ptr current_move_generator; + + //Define the timing bb weight factor for the agent's reward function + float timing_bb_factor = REWARD_BB_TIMING_RELATIVE_WEIGHT; + + if (skip_anneal == false) { + //Table header + VTR_LOG("\n"); + print_place_status_header(); + + /* Outer loop of the simulated annealing begins */ + do { + vtr::Timer temperature_timer; + + outer_loop_update_timing_info(placer_opts, &costs, num_connections, + state.crit_exponent, &outer_crit_iter_count, + place_delay_model.get(), placer_criticalities.get(), + placer_setup_slacks.get(), pin_timing_invalidator.get(), + timing_info.get()); + + if (placer_opts.place_algorithm.is_timing_driven()) { + critical_path = timing_info->least_slack_critical_path(); + sTNS = timing_info->setup_total_negative_slack(); + sWNS = timing_info->setup_worst_negative_slack(); + + //see if we should save the current placement solution as a checkpoint + + if (placer_opts.place_checkpointing + && agent_state == LATE_IN_THE_ANNEAL) { + save_placement_checkpoint_if_needed(placement_checkpoint, + timing_info, costs, critical_path.delay()); + } + } + + //move the appropoiate move_generator to be the current used move generator + assign_current_move_generator(move_generator, move_generator2, + agent_state, placer_opts, false, current_move_generator); + + //do a complete inner loop iteration + placement_inner_loop(&state, placer_opts, inner_recompute_limit, + &stats, &costs, &moves_since_cost_recompute, + pin_timing_invalidator.get(), place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + *current_move_generator, *manual_move_generator, + blocks_affected, timing_info.get(), + placer_opts.place_algorithm, move_type_stat, + timing_bb_factor); + + //move the update used move_generator to its original variable + update_move_generator(move_generator, move_generator2, agent_state, + placer_opts, false, current_move_generator); + + tot_iter += state.move_lim; + ++state.num_temps; + + print_place_status(state, stats, temperature_timer.elapsed_sec(), + critical_path.delay(), sTNS, sWNS, tot_iter); + if (placer_opts.place_algorithm.is_timing_driven() + && placer_opts.place_agent_multistate + && agent_state == EARLY_IN_THE_ANNEAL) { + if (state.alpha < 0.85 && state.alpha > 0.6) { + agent_state = LATE_IN_THE_ANNEAL; + VTR_LOG("Agent's 2nd state: \n"); + } + } + + sprintf(msg, "Cost: %g BB Cost %g TD Cost %g Temperature: %g", + costs.cost, costs.bb_cost, costs.timing_cost, state.t); + update_screen(ScreenUpdatePriority::MINOR, msg, PLACEMENT, + timing_info); #ifdef VERBOSE if (getEchoEnabled()) { print_clb_placement("first_iteration_clb_placement.echo"); } #endif - } while (state.outer_loop_update(stats.success_rate, costs, placer_opts, - annealing_sched)); - /* Outer loop of the simmulated annealing ends */ - } //skip_anneal ends - - /* Start Quench */ - state.t = 0; //Freeze out: only accept solutions that improve placement. - state.move_lim = state.move_lim_max; //Revert the move limit to initial value. - - auto pre_quench_timing_stats = timing_ctx.stats; - { /* Quench */ - - vtr::ScopedFinishTimer temperature_timer("Placement Quench"); - - outer_loop_update_timing_info(placer_opts, &costs, num_connections, - state.crit_exponent, &outer_crit_iter_count, - place_delay_model.get(), placer_criticalities.get(), - placer_setup_slacks.get(), pin_timing_invalidator.get(), - timing_info.get()); - - //move the appropoiate move_generator to be the current used move generator - assign_current_move_generator(move_generator, move_generator2, - agent_state, placer_opts, true, current_move_generator); - - /* Run inner loop again with temperature = 0 so as to accept only swaps - * which reduce the cost of the placement */ - placement_inner_loop(&state, placer_opts, quench_recompute_limit, - &stats, &costs, &moves_since_cost_recompute, - pin_timing_invalidator.get(), place_delay_model.get(), - placer_criticalities.get(), placer_setup_slacks.get(), - *current_move_generator, *manual_move_generator, - blocks_affected, timing_info.get(), - placer_opts.place_quench_algorithm, move_type_stat, - timing_bb_factor); - - //move the update used move_generator to its original variable - update_move_generator(move_generator, move_generator2, agent_state, - placer_opts, true, current_move_generator); - - tot_iter += state.move_lim; - ++state.num_temps; - - if (placer_opts.place_quench_algorithm.is_timing_driven()) { - critical_path = timing_info->least_slack_critical_path(); - sTNS = timing_info->setup_total_negative_slack(); - sWNS = timing_info->setup_worst_negative_slack(); - } - - print_place_status(state, stats, temperature_timer.elapsed_sec(), - critical_path.delay(), sTNS, sWNS, tot_iter); - } - auto post_quench_timing_stats = timing_ctx.stats; - - //Final timing analysis - PlaceCritParams crit_params; - crit_params.crit_exponent = state.crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - if (placer_opts.place_algorithm.is_timing_driven()) { - perform_full_timing_update(crit_params, place_delay_model.get(), - placer_criticalities.get(), placer_setup_slacks.get(), - pin_timing_invalidator.get(), timing_info.get(), &costs); - VTR_LOG("post-quench CPD = %g (ns) \n", - 1e9 * timing_info->least_slack_critical_path().delay()); - } - - //See if our latest checkpoint is better than the current placement solution - if (placer_opts.place_checkpointing) - restore_best_placement(placement_checkpoint, timing_info, costs, - placer_criticalities, placer_setup_slacks, place_delay_model, - pin_timing_invalidator, crit_params); - - if (placer_opts.placement_saves_per_temperature >= 1) { - std::string filename = vtr::string_fmt("placement_%03d_%03d.place", - state.num_temps + 1, 0); - VTR_LOG("Saving final placement to file: %s\n", filename.c_str()); - print_place(nullptr, nullptr, filename.c_str()); - } - - // TODO: - // 1. add some subroutine hierarchy! Too big! + } while (state.outer_loop_update(stats.success_rate, costs, placer_opts, + annealing_sched)); + /* Outer loop of the simmulated annealing ends */ + } //skip_anneal ends + + /* Start Quench */ + state.t = 0; //Freeze out: only accept solutions that improve placement. + state.move_lim = state.move_lim_max; //Revert the move limit to initial value. + + auto pre_quench_timing_stats = timing_ctx.stats; + { /* Quench */ + + vtr::ScopedFinishTimer temperature_timer("Placement Quench"); + + outer_loop_update_timing_info(placer_opts, &costs, num_connections, + state.crit_exponent, &outer_crit_iter_count, + place_delay_model.get(), placer_criticalities.get(), + placer_setup_slacks.get(), pin_timing_invalidator.get(), + timing_info.get()); + + //move the appropoiate move_generator to be the current used move generator + assign_current_move_generator(move_generator, move_generator2, + agent_state, placer_opts, true, current_move_generator); + + /* Run inner loop again with temperature = 0 so as to accept only swaps + * which reduce the cost of the placement */ + placement_inner_loop(&state, placer_opts, quench_recompute_limit, + &stats, &costs, &moves_since_cost_recompute, + pin_timing_invalidator.get(), place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + *current_move_generator, *manual_move_generator, + blocks_affected, timing_info.get(), + placer_opts.place_quench_algorithm, move_type_stat, + timing_bb_factor); + + //move the update used move_generator to its original variable + update_move_generator(move_generator, move_generator2, agent_state, + placer_opts, true, current_move_generator); + + tot_iter += state.move_lim; + ++state.num_temps; + + if (placer_opts.place_quench_algorithm.is_timing_driven()) { + critical_path = timing_info->least_slack_critical_path(); + sTNS = timing_info->setup_total_negative_slack(); + sWNS = timing_info->setup_worst_negative_slack(); + } + + print_place_status(state, stats, temperature_timer.elapsed_sec(), + critical_path.delay(), sTNS, sWNS, tot_iter); + } + auto post_quench_timing_stats = timing_ctx.stats; + + //Final timing analysis + PlaceCritParams crit_params; + crit_params.crit_exponent = state.crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + if (placer_opts.place_algorithm.is_timing_driven()) { + perform_full_timing_update(crit_params, place_delay_model.get(), + placer_criticalities.get(), placer_setup_slacks.get(), + pin_timing_invalidator.get(), timing_info.get(), &costs); + VTR_LOG("post-quench CPD = %g (ns) \n", + 1e9 * timing_info->least_slack_critical_path().delay()); + } + + //See if our latest checkpoint is better than the current placement solution + if (placer_opts.place_checkpointing) + restore_best_placement(placement_checkpoint, timing_info, costs, + placer_criticalities, placer_setup_slacks, place_delay_model, + pin_timing_invalidator, crit_params); + + if (placer_opts.placement_saves_per_temperature >= 1) { + std::string filename = vtr::string_fmt("placement_%03d_%03d.place", + state.num_temps + 1, 0); + VTR_LOG("Saving final placement to file: %s\n", filename.c_str()); + print_place(nullptr, nullptr, filename.c_str()); + } + + // TODO: + // 1. add some subroutine hierarchy! Too big! #ifdef VERBOSE if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_END_CLB_PLACEMENT)) { @@ -879,167 +901,178 @@ void try_place(const t_placer_opts &placer_opts, } #endif - check_place(costs, place_delay_model.get(), placer_criticalities.get(), - placer_opts.place_algorithm); - - //Some stats - VTR_LOG("\n"); - VTR_LOG("Swaps called: %d\n", num_ts_called); - report_aborted_moves(); - - if (placer_opts.place_algorithm.is_timing_driven()) { - //Final timing estimate - VTR_ASSERT(timing_info); - - critical_path = timing_info->least_slack_critical_path(); - - if (isEchoFileEnabled(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH)) { - tatum::write_echo( - getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH), - *timing_ctx.graph, *timing_ctx.constraints, - *placement_delay_calc, timing_info->analyzer()); - - tatum::NodeId debug_tnode = id_or_pin_name_to_tnode( - analysis_opts.echo_dot_timing_graph_node); - write_setup_timing_graph_dot( - getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH) - + std::string(".dot"), *timing_info, debug_tnode); - } - - generate_post_place_timing_reports(placer_opts, analysis_opts, - *timing_info, *placement_delay_calc); - - /* Print critical path delay metrics */ - VTR_LOG("\n"); - print_setup_timing_summary(*timing_ctx.constraints, - *timing_info->setup_analyzer(), "Placement estimated "); - } - - sprintf(msg, - "Placement. Cost: %g bb_cost: %g td_cost: %g Channel Factor: %d", - costs.cost, costs.bb_cost, costs.timing_cost, width_fac); - VTR_LOG("Placement cost: %g, bb_cost: %g, td_cost: %g, \n", costs.cost, - costs.bb_cost, costs.timing_cost); - update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); - // Print out swap statistics - print_resources_utilization(); - - print_placement_swaps_stats(state); - - print_placement_move_types_stats(move_type_stat); - - free_placement_structs(placer_opts); - free_try_swap_arrays(); - - print_timing_stats("Placement Quench", post_quench_timing_stats, - pre_quench_timing_stats); - print_timing_stats("Placement Total ", timing_ctx.stats, - pre_place_timing_stats); - - VTR_LOG("update_td_costs: connections %g nets %g sum_nets %g total %g\n", - p_runtime_ctx.f_update_td_costs_connections_elapsed_sec, - p_runtime_ctx.f_update_td_costs_nets_elapsed_sec, - p_runtime_ctx.f_update_td_costs_sum_nets_elapsed_sec, - p_runtime_ctx.f_update_td_costs_total_elapsed_sec); + check_place(costs, place_delay_model.get(), placer_criticalities.get(), + placer_opts.place_algorithm); + + //Some stats + VTR_LOG("\n"); + VTR_LOG("Swaps called: %d\n", num_ts_called); + report_aborted_moves(); + + if (placer_opts.place_algorithm.is_timing_driven()) { + //Final timing estimate + VTR_ASSERT(timing_info); + + critical_path = timing_info->least_slack_critical_path(); + + if (isEchoFileEnabled(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH)) { + tatum::write_echo( + getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH), + *timing_ctx.graph, *timing_ctx.constraints, + *placement_delay_calc, timing_info->analyzer()); + + tatum::NodeId debug_tnode = id_or_pin_name_to_tnode( + analysis_opts.echo_dot_timing_graph_node); + write_setup_timing_graph_dot( + getEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH) + + std::string(".dot"), + *timing_info, debug_tnode); + } + + generate_post_place_timing_reports(placer_opts, analysis_opts, + *timing_info, *placement_delay_calc); + + /* Print critical path delay metrics */ + VTR_LOG("\n"); + print_setup_timing_summary(*timing_ctx.constraints, + *timing_info->setup_analyzer(), "Placement estimated "); + } + + sprintf(msg, + "Placement. Cost: %g bb_cost: %g td_cost: %g Channel Factor: %d", + costs.cost, costs.bb_cost, costs.timing_cost, width_fac); + VTR_LOG("Placement cost: %g, bb_cost: %g, td_cost: %g, \n", costs.cost, + costs.bb_cost, costs.timing_cost); + update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); + // Print out swap statistics + print_resources_utilization(); + + print_placement_swaps_stats(state); + + print_placement_move_types_stats(move_type_stat); + + free_placement_structs(placer_opts); + free_try_swap_arrays(); + + print_timing_stats("Placement Quench", post_quench_timing_stats, + pre_quench_timing_stats); + print_timing_stats("Placement Total ", timing_ctx.stats, + pre_place_timing_stats); + + VTR_LOG("update_td_costs: connections %g nets %g sum_nets %g total %g\n", + p_runtime_ctx.f_update_td_costs_connections_elapsed_sec, + p_runtime_ctx.f_update_td_costs_nets_elapsed_sec, + p_runtime_ctx.f_update_td_costs_sum_nets_elapsed_sec, + p_runtime_ctx.f_update_td_costs_total_elapsed_sec); } /* Function to update the setup slacks and criticalities before the inner loop of the annealing/quench */ -static void outer_loop_update_timing_info(const t_placer_opts &placer_opts, - t_placer_costs *costs, int num_connections, float crit_exponent, - int *outer_crit_iter_count, const PlaceDelayModel *delay_model, - PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - SetupTimingInfo *timing_info) { - if (!placer_opts.place_algorithm.is_timing_driven()) { - return; - } - - /*at each temperature change we update these values to be used */ - /*for normalizing the tradeoff between timing and wirelength (bb) */ - if (*outer_crit_iter_count >= placer_opts.recompute_crit_iter - || placer_opts.inner_loop_recompute_divider != 0) { +static void outer_loop_update_timing_info(const t_placer_opts& placer_opts, + t_placer_costs* costs, + int num_connections, + float crit_exponent, + int* outer_crit_iter_count, + const PlaceDelayModel* delay_model, + PlacerCriticalities* criticalities, + PlacerSetupSlacks* setup_slacks, + ClusteredPinTimingInvalidator* pin_timing_invalidator, + SetupTimingInfo* timing_info) { + if (!placer_opts.place_algorithm.is_timing_driven()) { + return; + } + + /*at each temperature change we update these values to be used */ + /*for normalizing the tradeoff between timing and wirelength (bb) */ + if (*outer_crit_iter_count >= placer_opts.recompute_crit_iter + || placer_opts.inner_loop_recompute_divider != 0) { #ifdef VERBOSE VTR_LOG("Outer loop recompute criticalities\n"); #endif - num_connections = std::max(num_connections, 1); //Avoid division by zero - VTR_ASSERT(num_connections > 0); + num_connections = std::max(num_connections, 1); //Avoid division by zero + VTR_ASSERT(num_connections > 0); - PlaceCritParams crit_params; - crit_params.crit_exponent = crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; + PlaceCritParams crit_params; + crit_params.crit_exponent = crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; - //Update all timing related classes - perform_full_timing_update(crit_params, delay_model, criticalities, - setup_slacks, pin_timing_invalidator, timing_info, costs); + //Update all timing related classes + perform_full_timing_update(crit_params, delay_model, criticalities, + setup_slacks, pin_timing_invalidator, timing_info, costs); - *outer_crit_iter_count = 0; - } - (*outer_crit_iter_count)++; + *outer_crit_iter_count = 0; + } + (*outer_crit_iter_count)++; - /* Update the cost normalization factors */ - costs->update_norm_factors(); + /* Update the cost normalization factors */ + costs->update_norm_factors(); } /* Function which contains the inner loop of the simulated annealing */ -static void placement_inner_loop(const t_annealing_state *state, - const t_placer_opts &placer_opts, int inner_recompute_limit, - t_placer_statistics *stats, t_placer_costs *costs, - int *moves_since_cost_recompute, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, - PlacerSetupSlacks *setup_slacks, MoveGenerator &move_generator, - ManualMoveGenerator &manual_move_generator, - t_pl_blocks_to_be_moved &blocks_affected, SetupTimingInfo *timing_info, - const t_place_algorithm &place_algorithm, MoveTypeStat &move_type_stat, - float timing_bb_factor) { - int inner_crit_iter_count, inner_iter; - - int inner_placement_save_count = 0; //How many times have we dumped placement to a file this temperature? - - stats->reset(); - - inner_crit_iter_count = 1; - - /* Inner loop begins */ - for (inner_iter = 0; inner_iter < state->move_lim; inner_iter++) { - e_move_result swap_result = try_swap(state, costs, move_generator, - manual_move_generator, timing_info, pin_timing_invalidator, - blocks_affected, delay_model, criticalities, setup_slacks, - placer_opts, move_type_stat, place_algorithm, timing_bb_factor); - - if (swap_result == ACCEPTED) { - /* Move was accepted. Update statistics that are useful for the annealing schedule. */ - stats->single_swap_update(*costs); - num_swap_accepted++; - } else if (swap_result == ABORTED) { - num_swap_aborted++; - } else { // swap_result == REJECTED - num_swap_rejected++; - } - - if (place_algorithm.is_timing_driven()) { - /* Do we want to re-timing analyze the circuit to get updated slack and criticality values? - * We do this only once in a while, since it is expensive. - */ - if (inner_crit_iter_count >= inner_recompute_limit - && inner_iter != state->move_lim - 1) { /*on last iteration don't recompute */ - - inner_crit_iter_count = 0; +static void placement_inner_loop(const t_annealing_state* state, + const t_placer_opts& placer_opts, + int inner_recompute_limit, + t_placer_statistics* stats, + t_placer_costs* costs, + int* moves_since_cost_recompute, + ClusteredPinTimingInvalidator* pin_timing_invalidator, + const PlaceDelayModel* delay_model, + PlacerCriticalities* criticalities, + PlacerSetupSlacks* setup_slacks, + MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, + t_pl_blocks_to_be_moved& blocks_affected, + SetupTimingInfo* timing_info, + const t_place_algorithm& place_algorithm, + MoveTypeStat& move_type_stat, + float timing_bb_factor) { + int inner_crit_iter_count, inner_iter; + + int inner_placement_save_count = 0; //How many times have we dumped placement to a file this temperature? + + stats->reset(); + + inner_crit_iter_count = 1; + + /* Inner loop begins */ + for (inner_iter = 0; inner_iter < state->move_lim; inner_iter++) { + e_move_result swap_result = try_swap(state, costs, move_generator, + manual_move_generator, timing_info, pin_timing_invalidator, + blocks_affected, delay_model, criticalities, setup_slacks, + placer_opts, move_type_stat, place_algorithm, timing_bb_factor); + + if (swap_result == ACCEPTED) { + /* Move was accepted. Update statistics that are useful for the annealing schedule. */ + stats->single_swap_update(*costs); + num_swap_accepted++; + } else if (swap_result == ABORTED) { + num_swap_aborted++; + } else { // swap_result == REJECTED + num_swap_rejected++; + } + + if (place_algorithm.is_timing_driven()) { + /* Do we want to re-timing analyze the circuit to get updated slack and criticality values? + * We do this only once in a while, since it is expensive. + */ + if (inner_crit_iter_count >= inner_recompute_limit + && inner_iter != state->move_lim - 1) { /*on last iteration don't recompute */ + + inner_crit_iter_count = 0; #ifdef VERBOSE VTR_LOG("Inner loop recompute criticalities\n"); #endif - PlaceCritParams crit_params; - crit_params.crit_exponent = state->crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - //Update all timing related classes - perform_full_timing_update(crit_params, delay_model, - criticalities, setup_slacks, pin_timing_invalidator, - timing_info, costs); - } - inner_crit_iter_count++; - } + PlaceCritParams crit_params; + crit_params.crit_exponent = state->crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + //Update all timing related classes + perform_full_timing_update(crit_params, delay_model, + criticalities, setup_slacks, pin_timing_invalidator, + timing_info, costs); + } + inner_crit_iter_count++; + } #ifdef VERBOSE VTR_LOG("t = %g cost = %g bb_cost = %g timing_cost = %g move = %d\n", t, costs->cost, costs->bb_cost, costs->timing_cost, inner_iter); @@ -1048,186 +1081,177 @@ static void placement_inner_loop(const t_annealing_state *state, "fabs((*bb_cost) - comp_bb_cost(CHECK)) > (*bb_cost) * ERROR_TOL"); #endif - /* Lines below prevent too much round-off error from accumulating - * in the cost over many iterations (due to incremental updates). - * This round-off can lead to error checks failing because the cost - * is different from what you get when you recompute from scratch. - */ - ++(*moves_since_cost_recompute); - if (*moves_since_cost_recompute > MAX_MOVES_BEFORE_RECOMPUTE) { - recompute_costs_from_scratch(placer_opts, delay_model, - criticalities, costs); - *moves_since_cost_recompute = 0; - } - - if (placer_opts.placement_saves_per_temperature >= 1 && inner_iter > 0 - && (inner_iter + 1) - % (state->move_lim - / placer_opts.placement_saves_per_temperature) - == 0) { - std::string filename = vtr::string_fmt("placement_%03d_%03d.place", - state->num_temps + 1, inner_placement_save_count); - VTR_LOG( - "Saving placement to file at temperature move %d / %d: %s\n", - inner_iter, state->move_lim, filename.c_str()); - print_place(nullptr, nullptr, filename.c_str()); - ++inner_placement_save_count; - } - } - - /* Calculate the success_rate and std_dev of the costs. */ - stats->calc_iteration_stats(*costs, state->move_lim); + /* Lines below prevent too much round-off error from accumulating + * in the cost over many iterations (due to incremental updates). + * This round-off can lead to error checks failing because the cost + * is different from what you get when you recompute from scratch. + */ + ++(*moves_since_cost_recompute); + if (*moves_since_cost_recompute > MAX_MOVES_BEFORE_RECOMPUTE) { + recompute_costs_from_scratch(placer_opts, delay_model, + criticalities, costs); + *moves_since_cost_recompute = 0; + } + + if (placer_opts.placement_saves_per_temperature >= 1 && inner_iter > 0 + && (inner_iter + 1) + % (state->move_lim + / placer_opts.placement_saves_per_temperature) + == 0) { + std::string filename = vtr::string_fmt("placement_%03d_%03d.place", + state->num_temps + 1, inner_placement_save_count); + VTR_LOG( + "Saving placement to file at temperature move %d / %d: %s\n", + inner_iter, state->move_lim, filename.c_str()); + print_place(nullptr, nullptr, filename.c_str()); + ++inner_placement_save_count; + } + } + + /* Calculate the success_rate and std_dev of the costs. */ + stats->calc_iteration_stats(*costs, state->move_lim); } -static void recompute_costs_from_scratch(const t_placer_opts &placer_opts, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, t_placer_costs *costs) { - double new_bb_cost = recompute_bb_cost(); - if (fabs(new_bb_cost - costs->bb_cost) > costs->bb_cost * ERROR_TOL) { - std::string msg = - vtr::string_fmt( - "in recompute_costs_from_scratch: new_bb_cost = %g, old bb_cost = %g\n", - new_bb_cost, costs->bb_cost); - VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); - } - costs->bb_cost = new_bb_cost; - - if (placer_opts.place_algorithm.is_timing_driven()) { - double new_timing_cost = 0.; - comp_td_costs(delay_model, *criticalities, &new_timing_cost); - if (fabs( - new_timing_cost - - costs->timing_cost) > costs->timing_cost * ERROR_TOL) { - std::string msg = - vtr::string_fmt( - "in recompute_costs_from_scratch: new_timing_cost = %g, old timing_cost = %g, ERROR_TOL = %g\n", - new_timing_cost, costs->timing_cost, ERROR_TOL); - VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); - } - costs->timing_cost = new_timing_cost; - } else { - VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); - - costs->cost = new_bb_cost; - } +static void recompute_costs_from_scratch(const t_placer_opts& placer_opts, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + t_placer_costs* costs) { + double new_bb_cost = recompute_bb_cost(); + if (fabs(new_bb_cost - costs->bb_cost) > costs->bb_cost * ERROR_TOL) { + std::string msg = vtr::string_fmt( + "in recompute_costs_from_scratch: new_bb_cost = %g, old bb_cost = %g\n", + new_bb_cost, costs->bb_cost); + VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); + } + costs->bb_cost = new_bb_cost; + + if (placer_opts.place_algorithm.is_timing_driven()) { + double new_timing_cost = 0.; + comp_td_costs(delay_model, *criticalities, &new_timing_cost); + if (fabs( + new_timing_cost + - costs->timing_cost) + > costs->timing_cost * ERROR_TOL) { + std::string msg = vtr::string_fmt( + "in recompute_costs_from_scratch: new_timing_cost = %g, old timing_cost = %g, ERROR_TOL = %g\n", + new_timing_cost, costs->timing_cost, ERROR_TOL); + VPR_ERROR(VPR_ERROR_PLACE, msg.c_str()); + } + costs->timing_cost = new_timing_cost; + } else { + VTR_ASSERT(placer_opts.place_algorithm == BOUNDING_BOX_PLACE); + + costs->cost = new_bb_cost; + } } /*only count non-global connections */ static int count_connections() { - int count = 0; + int count = 0; - auto &cluster_ctx = g_vpr_ctx.clustering(); - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) - continue; + auto& cluster_ctx = g_vpr_ctx.clustering(); + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + continue; - count += cluster_ctx.clb_nlist.net_sinks(net_id).size(); - } + count += cluster_ctx.clb_nlist.net_sinks(net_id).size(); + } - return (count); + return (count); } ///@brief Find the starting temperature for the annealing loop. -static float starting_t(const t_annealing_state *state, t_placer_costs *costs, - t_annealing_sched annealing_sched, const PlaceDelayModel *delay_model, - PlacerCriticalities *criticalities, PlacerSetupSlacks *setup_slacks, - SetupTimingInfo *timing_info, MoveGenerator &move_generator, - ManualMoveGenerator &manual_move_generator, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - t_pl_blocks_to_be_moved &blocks_affected, - const t_placer_opts &placer_opts, MoveTypeStat &move_type_stat) { - if (annealing_sched.type == USER_SCHED) { - return (annealing_sched.init_t); - } - - auto &cluster_ctx = g_vpr_ctx.clustering(); - - /* Use to calculate the average of cost when swap is accepted. */ - int num_accepted = 0; - - /* Use double types to avoid round off. */ - double av = 0., sum_of_squares = 0.; - - /* Determines the block swap loop count. */ - int move_lim = std::min(state->move_lim_max, - (int) cluster_ctx.clb_nlist.blocks().size()); - - - for (int i = 0; i < move_lim; i++) { - - //Checks manual move flag for manual move feature - get_manual_move_flag(); - - //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack - e_move_result swap_result = try_swap(state, costs, move_generator, - manual_move_generator, timing_info, pin_timing_invalidator, - blocks_affected, delay_model, criticalities, setup_slacks, - placer_opts, move_type_stat, placer_opts.place_algorithm, - REWARD_BB_TIMING_RELATIVE_WEIGHT); - - if (swap_result == ACCEPTED) { - num_accepted++; - av += costs->cost; - sum_of_squares += costs->cost * costs->cost; - num_swap_accepted++; - } else if (swap_result == ABORTED) { - num_swap_aborted++; - } else { - num_swap_rejected++; - } - } - - /* Take the average of the accepted swaps' cost values. */ - av = num_accepted > 0 ? (av / num_accepted) : 0.; - - /* Get the standard deviation. */ - double std_dev = get_std_dev(num_accepted, sum_of_squares, av); - - /* Print warning if not all swaps are accepted. */ - if (num_accepted != move_lim) { - VTR_LOG_WARN("Starting t: %d of %d configurations accepted.\n", - num_accepted, move_lim); - } +static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t_annealing_sched annealing_sched, const PlaceDelayModel* delay_model, PlacerCriticalities* criticalities, PlacerSetupSlacks* setup_slacks, SetupTimingInfo* timing_info, MoveGenerator& move_generator, ManualMoveGenerator& manual_move_generator, ClusteredPinTimingInvalidator* pin_timing_invalidator, t_pl_blocks_to_be_moved& blocks_affected, const t_placer_opts& placer_opts, MoveTypeStat& move_type_stat) { + if (annealing_sched.type == USER_SCHED) { + return (annealing_sched.init_t); + } + + auto& cluster_ctx = g_vpr_ctx.clustering(); + + /* Use to calculate the average of cost when swap is accepted. */ + int num_accepted = 0; + + /* Use double types to avoid round off. */ + double av = 0., sum_of_squares = 0.; + + /* Determines the block swap loop count. */ + int move_lim = std::min(state->move_lim_max, + (int)cluster_ctx.clb_nlist.blocks().size()); + + for (int i = 0; i < move_lim; i++) { + //Checks manual move flag for manual move feature + get_manual_move_flag(); + + //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack + e_move_result swap_result = try_swap(state, costs, move_generator, + manual_move_generator, timing_info, pin_timing_invalidator, + blocks_affected, delay_model, criticalities, setup_slacks, + placer_opts, move_type_stat, placer_opts.place_algorithm, + REWARD_BB_TIMING_RELATIVE_WEIGHT); + + if (swap_result == ACCEPTED) { + num_accepted++; + av += costs->cost; + sum_of_squares += costs->cost * costs->cost; + num_swap_accepted++; + } else if (swap_result == ABORTED) { + num_swap_aborted++; + } else { + num_swap_rejected++; + } + } + + /* Take the average of the accepted swaps' cost values. */ + av = num_accepted > 0 ? (av / num_accepted) : 0.; + + /* Get the standard deviation. */ + double std_dev = get_std_dev(num_accepted, sum_of_squares, av); + + /* Print warning if not all swaps are accepted. */ + if (num_accepted != move_lim) { + VTR_LOG_WARN("Starting t: %d of %d configurations accepted.\n", + num_accepted, move_lim); + } #ifdef VERBOSE /* Print stats related to finding the initital temp. */ VTR_LOG("std_dev: %g, average cost: %g, starting temp: %g\n", std_dev, av, 20. * std_dev); #endif - /* Set the initial temperature to 20 times the standard of deviation */ - /* so that the initial temperature adjusts according to the circuit */ - return (20. * std_dev); + /* Set the initial temperature to 20 times the standard of deviation */ + /* so that the initial temperature adjusts according to the circuit */ + return (20. * std_dev); } static void update_move_nets(int num_nets_affected) { - /* update net cost functions and reset flags. */ - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_move_ctx = g_placer_ctx.mutable_move(); + /* update net cost functions and reset flags. */ + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_move_ctx = g_placer_ctx.mutable_move(); - for (int inet_affected = 0; inet_affected < num_nets_affected; - inet_affected++) { - ClusterNetId net_id = ts_nets_to_update[inet_affected]; + for (int inet_affected = 0; inet_affected < num_nets_affected; + inet_affected++) { + ClusterNetId net_id = ts_nets_to_update[inet_affected]; - place_move_ctx.bb_coords[net_id] = ts_bb_coord_new[net_id]; - if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET) - place_move_ctx.bb_num_on_edges[net_id] = ts_bb_edge_new[net_id]; + place_move_ctx.bb_coords[net_id] = ts_bb_coord_new[net_id]; + if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET) + place_move_ctx.bb_num_on_edges[net_id] = ts_bb_edge_new[net_id]; - net_cost[net_id] = proposed_net_cost[net_id]; + net_cost[net_id] = proposed_net_cost[net_id]; - /* negative proposed_net_cost value is acting as a flag. */ - proposed_net_cost[net_id] = -1; - bb_updated_before[net_id] = NOT_UPDATED_YET; - } + /* negative proposed_net_cost value is acting as a flag. */ + proposed_net_cost[net_id] = -1; + bb_updated_before[net_id] = NOT_UPDATED_YET; + } } static void reset_move_nets(int num_nets_affected) { - /* Reset the net cost function flags first. */ - for (int inet_affected = 0; inet_affected < num_nets_affected; - inet_affected++) { - ClusterNetId net_id = ts_nets_to_update[inet_affected]; - proposed_net_cost[net_id] = -1; - bb_updated_before[net_id] = NOT_UPDATED_YET; - } + /* Reset the net cost function flags first. */ + for (int inet_affected = 0; inet_affected < num_nets_affected; + inet_affected++) { + ClusterNetId net_id = ts_nets_to_update[inet_affected]; + proposed_net_cost[net_id] = -1; + bb_updated_before[net_id] = NOT_UPDATED_YET; + } } /** @@ -1246,266 +1270,269 @@ static void reset_move_nets(int num_nets_affected) { * * @return Whether the block swap is accepted, rejected or aborted. */ -static e_move_result try_swap(const t_annealing_state *state, - t_placer_costs *costs, MoveGenerator &move_generator, - ManualMoveGenerator &manual_move_generator, - SetupTimingInfo *timing_info, - ClusteredPinTimingInvalidator *pin_timing_invalidator, - t_pl_blocks_to_be_moved &blocks_affected, - const PlaceDelayModel *delay_model, PlacerCriticalities *criticalities, - PlacerSetupSlacks *setup_slacks, const t_placer_opts &placer_opts, - MoveTypeStat &move_type_stat, const t_place_algorithm &place_algorithm, - float timing_bb_factor) { - /* Picks some block and moves it to another spot. If this spot is * - * occupied, switch the blocks. Assess the change in cost function. * - * rlim is the range limiter. * - * Returns whether the swap is accepted, rejected or aborted. * - * Passes back the new value of the cost functions. */ - - float rlim_escape_fraction = placer_opts.rlim_escape_fraction; - float timing_tradeoff = placer_opts.timing_tradeoff; - - PlaceCritParams crit_params; - crit_params.crit_exponent = state->crit_exponent; - crit_params.crit_limit = placer_opts.place_crit_limit; - - e_move_type move_type; //move type number - - num_ts_called++; - - MoveOutcomeStats move_outcome_stats; - - /* I'm using negative values of proposed_net_cost as a flag, * - * so DO NOT use cost functions that can go negative. */ - - double delta_c = 0; //Change in cost due to this swap. - double bb_delta_c = 0; //Change in the bounding box (wiring) cost. - double timing_delta_c = 0; //Change in the timing cost (delay * criticality). - - /* Allow some fraction of moves to not be restricted by rlim, */ - /* in the hopes of better escaping local minima. */ - float rlim; - if (rlim_escape_fraction > 0. && vtr::frand() < rlim_escape_fraction) { - rlim = std::numeric_limits::infinity(); - } else { - rlim = state->rlim; - } - - ManualMovesGlobals *manual_move_global = get_manual_moves_global(); - - e_create_move create_move_outcome; - - if(manual_move_global->manual_move_flag) { - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - - create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); - } - else { - //Generate a new move (perturbation) used to explore the space of possible placements - create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); - } - - ++move_type_stat.num_moves[(int) move_type]; - LOG_MOVE_STATS_PROPOSED(t, blocks_affected); - - e_move_result move_outcome = ABORTED; - - if (create_move_outcome == e_create_move::ABORT) { - LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN(), - std::numeric_limits::quiet_NaN(), "ABORTED", - "illegal move"); - - move_outcome = ABORTED; - - ++move_type_stat.aborted_moves[(int) move_type]; - } else { - VTR_ASSERT(create_move_outcome == e_create_move::VALID); - - /* - * To make evaluating the move simpler (e.g. calculating changed bounding box), - * we first move the blocks to their new locations (apply the move to - * place_ctx.block_locs) and then compute the change in cost. If the move - * is accepted, the inverse look-up in place_ctx.grid_blocks is updated - * (committing the move). If the move is rejected, the blocks are returned to - * their original positions (reverting place_ctx.block_locs to its original state). - * - * Note that the inverse look-up place_ctx.grid_blocks is only updated after - * move acceptance is determined, so it should not be used when evaluating a move. - */ - - /* Update the block positions */ - apply_move_blocks(blocks_affected); - - //Find all the nets affected by this swap and update the wiring costs. - //This cost value doesn't depend on the timing info. - // - //Also find all the pins affected by the swap, and calculates new connection - //delays and timing costs and store them in proposed_* data structures. - int num_nets_affected = find_affected_nets_and_update_costs( - place_algorithm, delay_model, criticalities, blocks_affected, - bb_delta_c, timing_delta_c); - - //For setup slack analysis, we first do a timing analysis to get the newest - //slack values resulted from the proposed block moves. If the move turns out - //to be accepted, we keep the updated slack values and commit the block moves. - //If rejected, we reject the proposed block moves and revert this timing analysis. - if (place_algorithm == SLACK_TIMING_PLACE) { - /* Invalidates timing of modified connections for incremental timing updates. */ - invalidate_affected_connections(blocks_affected, - pin_timing_invalidator, timing_info); - - /* Update the connection_timing_cost and connection_delay * - * values from the temporary values. */ - commit_td_cost(blocks_affected); - - /* Update timing information. Since we are analyzing setup slacks, * - * we only update those values and keep the criticalities stale * - * so as not to interfere with the original timing driven algorithm. * - * - * Note: the timing info must be updated after applying block moves * - * and committing the timing driven delays and costs. * - * If we wish to revert this timing update due to move rejection, * - * we need to revert block moves and restore the timing values. */ - criticalities->disable_update(); - setup_slacks->enable_update(); - update_timing_classes(crit_params, timing_info, criticalities, - setup_slacks, pin_timing_invalidator); - - /* Get the setup slack analysis cost */ - //TODO: calculate a weighted average of the slack cost and wiring cost - delta_c = analyze_setup_slack_cost(setup_slacks); - } else if (place_algorithm == CRITICALITY_TIMING_PLACE) { - /* Take delta_c as a combination of timing and wiring cost. In - * addition to `timing_tradeoff`, we normalize the cost values */ - delta_c = (1 - timing_tradeoff) * bb_delta_c * costs->bb_cost_norm - + timing_tradeoff * timing_delta_c - * costs->timing_cost_norm; - } else { - VTR_ASSERT_SAFE(place_algorithm == BOUNDING_BOX_PLACE); - delta_c = bb_delta_c; - } - - /* 1 -> move accepted, 0 -> rejected. */ - move_outcome = assess_swap(delta_c, state->t); - - if (manual_move_global->manual_move_flag) { - update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); - cost_summary_dialog(); - - //User accepts or rejects the move. - move_outcome = manual_move_global->manual_move_info.user_move_outcome; - } - - if (move_outcome == ACCEPTED) { - costs->cost += delta_c; - costs->bb_cost += bb_delta_c; - - if (place_algorithm == SLACK_TIMING_PLACE) { - /* Update the timing driven cost as usual */ - costs->timing_cost += timing_delta_c; - - //Commit the setup slack information - //The timing delay and cost values should be committed already - commit_setup_slacks(setup_slacks); - } - - if (place_algorithm == CRITICALITY_TIMING_PLACE) { - costs->timing_cost += timing_delta_c; - - /* Invalidates timing of modified connections for incremental * - * timing updates. These invalidations are accumulated for a * - * big timing update in the outer loop. */ - invalidate_affected_connections(blocks_affected, - pin_timing_invalidator, timing_info); - - /* Update the connection_timing_cost and connection_delay * - * values from the temporary values. */ - commit_td_cost(blocks_affected); - } - - /* Update net cost functions and reset flags. */ - update_move_nets(num_nets_affected); - - /* Update clb data structures since we kept the move. */ - commit_move_blocks(blocks_affected); - - ++move_type_stat.accepted_moves[(int) move_type]; - - //Highlights the new block when manual move is selected. - highlight_new_block_location(manual_move_global->manual_move_flag); - - } else { - VTR_ASSERT_SAFE(move_outcome == REJECTED); - - /* Reset the net cost function flags first. */ - reset_move_nets(num_nets_affected); - - /* Restore the place_ctx.block_locs data structures to their state before the move. */ - revert_move_blocks(blocks_affected); - - if (place_algorithm == SLACK_TIMING_PLACE) { - /* Revert the timing delays and costs to pre-update values. */ - /* These routines must be called after reverting the block moves. */ - //TODO: make this process incremental - comp_td_connection_delays(delay_model); - comp_td_costs(delay_model, *criticalities, &costs->timing_cost); - - /* Re-invalidate the affected sink pins since the proposed * - * move is rejected, and the same blocks are reverted to * - * their original positions. */ - invalidate_affected_connections(blocks_affected, - pin_timing_invalidator, timing_info); - - /* Revert the timing update */ - update_timing_classes(crit_params, timing_info, criticalities, - setup_slacks, pin_timing_invalidator); - - VTR_ASSERT_SAFE_MSG( - verify_connection_setup_slacks(setup_slacks), - "The current setup slacks should be identical to the values before the try swap timing info update."); - } - - if (place_algorithm == CRITICALITY_TIMING_PLACE) { - /* Unstage the values stored in proposed_* data structures */ - revert_td_cost(blocks_affected); - } - } - - move_outcome_stats.delta_cost_norm = delta_c; - move_outcome_stats.delta_bb_cost_norm = bb_delta_c - * costs->bb_cost_norm; - move_outcome_stats.delta_timing_cost_norm = timing_delta_c - * costs->timing_cost_norm; - - move_outcome_stats.delta_bb_cost_abs = bb_delta_c; - move_outcome_stats.delta_timing_cost_abs = timing_delta_c; - - LOG_MOVE_STATS_OUTCOME(delta_c, bb_delta_c, timing_delta_c, - (move_outcome ? "ACCEPTED" : "REJECTED"), ""); - } - move_outcome_stats.outcome = move_outcome; +static e_move_result try_swap(const t_annealing_state* state, + t_placer_costs* costs, + MoveGenerator& move_generator, + ManualMoveGenerator& manual_move_generator, + SetupTimingInfo* timing_info, + ClusteredPinTimingInvalidator* pin_timing_invalidator, + t_pl_blocks_to_be_moved& blocks_affected, + const PlaceDelayModel* delay_model, + PlacerCriticalities* criticalities, + PlacerSetupSlacks* setup_slacks, + const t_placer_opts& placer_opts, + MoveTypeStat& move_type_stat, + const t_place_algorithm& place_algorithm, + float timing_bb_factor) { + /* Picks some block and moves it to another spot. If this spot is * + * occupied, switch the blocks. Assess the change in cost function. * + * rlim is the range limiter. * + * Returns whether the swap is accepted, rejected or aborted. * + * Passes back the new value of the cost functions. */ + + float rlim_escape_fraction = placer_opts.rlim_escape_fraction; + float timing_tradeoff = placer_opts.timing_tradeoff; + + PlaceCritParams crit_params; + crit_params.crit_exponent = state->crit_exponent; + crit_params.crit_limit = placer_opts.place_crit_limit; + + e_move_type move_type; //move type number + + num_ts_called++; + + MoveOutcomeStats move_outcome_stats; + + /* I'm using negative values of proposed_net_cost as a flag, * + * so DO NOT use cost functions that can go negative. */ + + double delta_c = 0; //Change in cost due to this swap. + double bb_delta_c = 0; //Change in the bounding box (wiring) cost. + double timing_delta_c = 0; //Change in the timing cost (delay * criticality). + + /* Allow some fraction of moves to not be restricted by rlim, */ + /* in the hopes of better escaping local minima. */ + float rlim; + if (rlim_escape_fraction > 0. && vtr::frand() < rlim_escape_fraction) { + rlim = std::numeric_limits::infinity(); + } else { + rlim = state->rlim; + } + + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + + e_create_move create_move_outcome; + + if (manual_move_global->manual_move_flag) { + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + + create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); + } else { + //Generate a new move (perturbation) used to explore the space of possible placements + create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + } + + ++move_type_stat.num_moves[(int)move_type]; + LOG_MOVE_STATS_PROPOSED(t, blocks_affected); + + e_move_result move_outcome = ABORTED; + + if (create_move_outcome == e_create_move::ABORT) { + LOG_MOVE_STATS_OUTCOME(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), "ABORTED", + "illegal move"); + + move_outcome = ABORTED; + + ++move_type_stat.aborted_moves[(int)move_type]; + } else { + VTR_ASSERT(create_move_outcome == e_create_move::VALID); + + /* + * To make evaluating the move simpler (e.g. calculating changed bounding box), + * we first move the blocks to their new locations (apply the move to + * place_ctx.block_locs) and then compute the change in cost. If the move + * is accepted, the inverse look-up in place_ctx.grid_blocks is updated + * (committing the move). If the move is rejected, the blocks are returned to + * their original positions (reverting place_ctx.block_locs to its original state). + * + * Note that the inverse look-up place_ctx.grid_blocks is only updated after + * move acceptance is determined, so it should not be used when evaluating a move. + */ + + /* Update the block positions */ + apply_move_blocks(blocks_affected); + + //Find all the nets affected by this swap and update the wiring costs. + //This cost value doesn't depend on the timing info. + // + //Also find all the pins affected by the swap, and calculates new connection + //delays and timing costs and store them in proposed_* data structures. + int num_nets_affected = find_affected_nets_and_update_costs( + place_algorithm, delay_model, criticalities, blocks_affected, + bb_delta_c, timing_delta_c); + + //For setup slack analysis, we first do a timing analysis to get the newest + //slack values resulted from the proposed block moves. If the move turns out + //to be accepted, we keep the updated slack values and commit the block moves. + //If rejected, we reject the proposed block moves and revert this timing analysis. + if (place_algorithm == SLACK_TIMING_PLACE) { + /* Invalidates timing of modified connections for incremental timing updates. */ + invalidate_affected_connections(blocks_affected, + pin_timing_invalidator, timing_info); + + /* Update the connection_timing_cost and connection_delay * + * values from the temporary values. */ + commit_td_cost(blocks_affected); + + /* Update timing information. Since we are analyzing setup slacks, * + * we only update those values and keep the criticalities stale * + * so as not to interfere with the original timing driven algorithm. * + * + * Note: the timing info must be updated after applying block moves * + * and committing the timing driven delays and costs. * + * If we wish to revert this timing update due to move rejection, * + * we need to revert block moves and restore the timing values. */ + criticalities->disable_update(); + setup_slacks->enable_update(); + update_timing_classes(crit_params, timing_info, criticalities, + setup_slacks, pin_timing_invalidator); + + /* Get the setup slack analysis cost */ + //TODO: calculate a weighted average of the slack cost and wiring cost + delta_c = analyze_setup_slack_cost(setup_slacks); + } else if (place_algorithm == CRITICALITY_TIMING_PLACE) { + /* Take delta_c as a combination of timing and wiring cost. In + * addition to `timing_tradeoff`, we normalize the cost values */ + delta_c = (1 - timing_tradeoff) * bb_delta_c * costs->bb_cost_norm + + timing_tradeoff * timing_delta_c + * costs->timing_cost_norm; + } else { + VTR_ASSERT_SAFE(place_algorithm == BOUNDING_BOX_PLACE); + delta_c = bb_delta_c; + } + + /* 1 -> move accepted, 0 -> rejected. */ + move_outcome = assess_swap(delta_c, state->t); + + if (manual_move_global->manual_move_flag) { + update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); + cost_summary_dialog(); + + //User accepts or rejects the move. + move_outcome = manual_move_global->manual_move_info.user_move_outcome; + } + + if (move_outcome == ACCEPTED) { + costs->cost += delta_c; + costs->bb_cost += bb_delta_c; + + if (place_algorithm == SLACK_TIMING_PLACE) { + /* Update the timing driven cost as usual */ + costs->timing_cost += timing_delta_c; + + //Commit the setup slack information + //The timing delay and cost values should be committed already + commit_setup_slacks(setup_slacks); + } + + if (place_algorithm == CRITICALITY_TIMING_PLACE) { + costs->timing_cost += timing_delta_c; + + /* Invalidates timing of modified connections for incremental * + * timing updates. These invalidations are accumulated for a * + * big timing update in the outer loop. */ + invalidate_affected_connections(blocks_affected, + pin_timing_invalidator, timing_info); + + /* Update the connection_timing_cost and connection_delay * + * values from the temporary values. */ + commit_td_cost(blocks_affected); + } + + /* Update net cost functions and reset flags. */ + update_move_nets(num_nets_affected); + + /* Update clb data structures since we kept the move. */ + commit_move_blocks(blocks_affected); + + ++move_type_stat.accepted_moves[(int)move_type]; + + //Highlights the new block when manual move is selected. + highlight_new_block_location(manual_move_global->manual_move_flag); + + } else { + VTR_ASSERT_SAFE(move_outcome == REJECTED); + + /* Reset the net cost function flags first. */ + reset_move_nets(num_nets_affected); + + /* Restore the place_ctx.block_locs data structures to their state before the move. */ + revert_move_blocks(blocks_affected); + + if (place_algorithm == SLACK_TIMING_PLACE) { + /* Revert the timing delays and costs to pre-update values. */ + /* These routines must be called after reverting the block moves. */ + //TODO: make this process incremental + comp_td_connection_delays(delay_model); + comp_td_costs(delay_model, *criticalities, &costs->timing_cost); + + /* Re-invalidate the affected sink pins since the proposed * + * move is rejected, and the same blocks are reverted to * + * their original positions. */ + invalidate_affected_connections(blocks_affected, + pin_timing_invalidator, timing_info); + + /* Revert the timing update */ + update_timing_classes(crit_params, timing_info, criticalities, + setup_slacks, pin_timing_invalidator); - calculate_reward_and_process_outcome(placer_opts, move_outcome_stats, - delta_c, timing_bb_factor, move_generator); + VTR_ASSERT_SAFE_MSG( + verify_connection_setup_slacks(setup_slacks), + "The current setup slacks should be identical to the values before the try swap timing info update."); + } + + if (place_algorithm == CRITICALITY_TIMING_PLACE) { + /* Unstage the values stored in proposed_* data structures */ + revert_td_cost(blocks_affected); + } + } + + move_outcome_stats.delta_cost_norm = delta_c; + move_outcome_stats.delta_bb_cost_norm = bb_delta_c + * costs->bb_cost_norm; + move_outcome_stats.delta_timing_cost_norm = timing_delta_c + * costs->timing_cost_norm; + + move_outcome_stats.delta_bb_cost_abs = bb_delta_c; + move_outcome_stats.delta_timing_cost_abs = timing_delta_c; + + LOG_MOVE_STATS_OUTCOME(delta_c, bb_delta_c, timing_delta_c, + (move_outcome ? "ACCEPTED" : "REJECTED"), ""); + } + move_outcome_stats.outcome = move_outcome; + + calculate_reward_and_process_outcome(placer_opts, move_outcome_stats, + delta_c, timing_bb_factor, move_generator); #ifdef VTR_ENABLE_DEBUG_LOGGING # ifndef NO_GRAPHICS - stop_placement_and_check_breakpoints(blocks_affected, move_outcome, delta_c, bb_delta_c, timing_delta_c); + stop_placement_and_check_breakpoints(blocks_affected, move_outcome, delta_c, bb_delta_c, timing_delta_c); # endif #endif - /* Clear the data structure containing block move info */ - clear_move_blocks(blocks_affected); + /* Clear the data structure containing block move info */ + clear_move_blocks(blocks_affected); - //VTR_ASSERT(check_macro_placement_consistency() == 0); + //VTR_ASSERT(check_macro_placement_consistency() == 0); #if 0 //Check that each accepted swap yields a valid placement check_place(*costs, delay_model, place_algorithm); #endif - return move_outcome; + return move_outcome; } /** @@ -1531,72 +1558,73 @@ static e_move_result try_swap(const t_annealing_state *state, * @return The number of affected nets. */ static int find_affected_nets_and_update_costs( - const t_place_algorithm &place_algorithm, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, - t_pl_blocks_to_be_moved &blocks_affected, double &bb_delta_c, - double &timing_delta_c) { - VTR_ASSERT_SAFE(bb_delta_c == 0.); - VTR_ASSERT_SAFE(timing_delta_c == 0.); - auto &cluster_ctx = g_vpr_ctx.clustering(); - - int num_affected_nets = 0; - - /* Go through all the blocks moved. */ - for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { - ClusterBlockId blk = blocks_affected.moved_blocks[iblk].block_num; - - /* Go through all the pins in the moved block. */ - for (ClusterPinId blk_pin : cluster_ctx.clb_nlist.block_pins(blk)) { - ClusterNetId net_id = cluster_ctx.clb_nlist.pin_net(blk_pin); - VTR_ASSERT_SAFE_MSG(net_id, - "Only valid nets should be found in compressed netlist block pins"); - - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) - //TODO: Do we require anyting special here for global nets? - //"Global nets are assumed to span the whole chip, and do not effect costs." - continue; - - /* Record effected nets */ - record_affected_net(net_id, num_affected_nets); - - /* Update the net bounding boxes. */ - update_net_bb(net_id, blocks_affected, iblk, blk, blk_pin); - - if (place_algorithm.is_timing_driven()) { - /* Determine the change in connection delay and timing cost. */ - update_td_delta_costs(delay_model, *criticalities, net_id, - blk_pin, blocks_affected, timing_delta_c); - } - } - } - - /* Now update the bounding box costs (since the net bounding * - * boxes are up-to-date). The cost is only updated once per net. */ - for (int inet_affected = 0; inet_affected < num_affected_nets; - inet_affected++) { - ClusterNetId net_id = ts_nets_to_update[inet_affected]; - - proposed_net_cost[net_id] = get_net_cost(net_id, - &ts_bb_coord_new[net_id]); - bb_delta_c += proposed_net_cost[net_id] - net_cost[net_id]; - } - - return num_affected_nets; + const t_place_algorithm& place_algorithm, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + t_pl_blocks_to_be_moved& blocks_affected, + double& bb_delta_c, + double& timing_delta_c) { + VTR_ASSERT_SAFE(bb_delta_c == 0.); + VTR_ASSERT_SAFE(timing_delta_c == 0.); + auto& cluster_ctx = g_vpr_ctx.clustering(); + + int num_affected_nets = 0; + + /* Go through all the blocks moved. */ + for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { + ClusterBlockId blk = blocks_affected.moved_blocks[iblk].block_num; + + /* Go through all the pins in the moved block. */ + for (ClusterPinId blk_pin : cluster_ctx.clb_nlist.block_pins(blk)) { + ClusterNetId net_id = cluster_ctx.clb_nlist.pin_net(blk_pin); + VTR_ASSERT_SAFE_MSG(net_id, + "Only valid nets should be found in compressed netlist block pins"); + + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + //TODO: Do we require anyting special here for global nets? + //"Global nets are assumed to span the whole chip, and do not effect costs." + continue; + + /* Record effected nets */ + record_affected_net(net_id, num_affected_nets); + + /* Update the net bounding boxes. */ + update_net_bb(net_id, blocks_affected, iblk, blk, blk_pin); + + if (place_algorithm.is_timing_driven()) { + /* Determine the change in connection delay and timing cost. */ + update_td_delta_costs(delay_model, *criticalities, net_id, + blk_pin, blocks_affected, timing_delta_c); + } + } + } + + /* Now update the bounding box costs (since the net bounding * + * boxes are up-to-date). The cost is only updated once per net. */ + for (int inet_affected = 0; inet_affected < num_affected_nets; + inet_affected++) { + ClusterNetId net_id = ts_nets_to_update[inet_affected]; + + proposed_net_cost[net_id] = get_net_cost(net_id, + &ts_bb_coord_new[net_id]); + bb_delta_c += proposed_net_cost[net_id] - net_cost[net_id]; + } + + return num_affected_nets; } ///@brief Record effected nets. static void record_affected_net(const ClusterNetId net, - int &num_affected_nets) { - /* Record effected nets. */ - if (proposed_net_cost[net] < 0.) { - /* Net not marked yet. */ - ts_nets_to_update[num_affected_nets] = net; - num_affected_nets++; - - /* Flag to say we've marked this net. */ - proposed_net_cost[net] = 1.; - } + int& num_affected_nets) { + /* Record effected nets. */ + if (proposed_net_cost[net] < 0.) { + /* Net not marked yet. */ + ts_nets_to_update[num_affected_nets] = net; + num_affected_nets++; + + /* Flag to say we've marked this net. */ + proposed_net_cost[net] = 1.; + } } /** @@ -1606,33 +1634,35 @@ static void record_affected_net(const ClusterNetId net, * be updated once per net, not once per pin. */ static void update_net_bb(const ClusterNetId net, - const t_pl_blocks_to_be_moved &blocks_affected, int iblk, - const ClusterBlockId blk, const ClusterPinId blk_pin) { - auto &cluster_ctx = g_vpr_ctx.clustering(); - - if (cluster_ctx.clb_nlist.net_sinks(net).size() < SMALL_NET) { - //For small nets brute-force bounding box update is faster - - if (bb_updated_before[net] == NOT_UPDATED_YET) { //Only once per-net - get_non_updateable_bb(net, &ts_bb_coord_new[net]); - } - } else { - //For large nets, update bounding box incrementally - int iblk_pin = tile_pin_index(blk_pin); - - t_physical_tile_type_ptr blk_type = physical_tile_type(blk); - int pin_width_offset = blk_type->pin_width_offset[iblk_pin]; - int pin_height_offset = blk_type->pin_height_offset[iblk_pin]; - - //Incremental bounding box update - update_bb(net, &ts_bb_coord_new[net], &ts_bb_edge_new[net], - blocks_affected.moved_blocks[iblk].old_loc.x + pin_width_offset, - blocks_affected.moved_blocks[iblk].old_loc.y - + pin_height_offset, - blocks_affected.moved_blocks[iblk].new_loc.x + pin_width_offset, - blocks_affected.moved_blocks[iblk].new_loc.y - + pin_height_offset); - } + const t_pl_blocks_to_be_moved& blocks_affected, + int iblk, + const ClusterBlockId blk, + const ClusterPinId blk_pin) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + + if (cluster_ctx.clb_nlist.net_sinks(net).size() < SMALL_NET) { + //For small nets brute-force bounding box update is faster + + if (bb_updated_before[net] == NOT_UPDATED_YET) { //Only once per-net + get_non_updateable_bb(net, &ts_bb_coord_new[net]); + } + } else { + //For large nets, update bounding box incrementally + int iblk_pin = tile_pin_index(blk_pin); + + t_physical_tile_type_ptr blk_type = physical_tile_type(blk); + int pin_width_offset = blk_type->pin_width_offset[iblk_pin]; + int pin_height_offset = blk_type->pin_height_offset[iblk_pin]; + + //Incremental bounding box update + update_bb(net, &ts_bb_coord_new[net], &ts_bb_edge_new[net], + blocks_affected.moved_blocks[iblk].old_loc.x + pin_width_offset, + blocks_affected.moved_blocks[iblk].old_loc.y + + pin_height_offset, + blocks_affected.moved_blocks[iblk].new_loc.x + pin_width_offset, + blocks_affected.moved_blocks[iblk].new_loc.y + + pin_height_offset); + } } /** @@ -1664,72 +1694,69 @@ static void update_net_bb(const ClusterNetId net, * This is also done to minimize the number of timing node/edge invalidations * for incremental static timing analysis (incremental STA). */ -static void update_td_delta_costs(const PlaceDelayModel *delay_model, - const PlacerCriticalities &criticalities, const ClusterNetId net, - const ClusterPinId pin, t_pl_blocks_to_be_moved &blocks_affected, - double &delta_timing_cost) { - auto &cluster_ctx = g_vpr_ctx.clustering(); - - const auto &connection_delay = g_placer_ctx.timing().connection_delay; - auto &connection_timing_cost = - g_placer_ctx.mutable_timing().connection_timing_cost; - auto &proposed_connection_delay = - g_placer_ctx.mutable_timing().proposed_connection_delay; - auto &proposed_connection_timing_cost = - g_placer_ctx.mutable_timing().proposed_connection_timing_cost; - - if (cluster_ctx.clb_nlist.pin_type(pin) == PinType::DRIVER) { - /* This pin is a net driver on a moved block. */ - /* Recompute all point to point connection delays for the net sinks. */ - for (size_t ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net).size(); - ipin++) { - float temp_delay = comp_td_single_connection_delay(delay_model, net, - ipin); - /* If the delay hasn't changed, do not mark this pin as affected */ - if (temp_delay == connection_delay[net][ipin]) { - continue; - } - - /* Calculate proposed delay and cost values */ - proposed_connection_delay[net][ipin] = temp_delay; - - proposed_connection_timing_cost[net][ipin] = - criticalities.criticality(net, ipin) * temp_delay; - delta_timing_cost += proposed_connection_timing_cost[net][ipin] - - connection_timing_cost[net][ipin]; - - /* Record this connection in blocks_affected.affected_pins */ - ClusterPinId sink_pin = cluster_ctx.clb_nlist.net_pin(net, ipin); - blocks_affected.affected_pins.push_back(sink_pin); - } - } else { - /* This pin is a net sink on a moved block */ - VTR_ASSERT_SAFE(cluster_ctx.clb_nlist.pin_type(pin) == PinType::SINK); - - /* Check if this sink's net is driven by a moved block */ - if (!driven_by_moved_block(net, blocks_affected)) { - /* Get the sink pin index in the net */ - int ipin = cluster_ctx.clb_nlist.pin_net_index(pin); - - float temp_delay = comp_td_single_connection_delay(delay_model, net, - ipin); - /* If the delay hasn't changed, do not mark this pin as affected */ - if (temp_delay == connection_delay[net][ipin]) { - return; - } - - /* Calculate proposed delay and cost values */ - proposed_connection_delay[net][ipin] = temp_delay; - - proposed_connection_timing_cost[net][ipin] = - criticalities.criticality(net, ipin) * temp_delay; - delta_timing_cost += proposed_connection_timing_cost[net][ipin] - - connection_timing_cost[net][ipin]; - - /* Record this connection in blocks_affected.affected_pins */ - blocks_affected.affected_pins.push_back(pin); - } - } +static void update_td_delta_costs(const PlaceDelayModel* delay_model, + const PlacerCriticalities& criticalities, + const ClusterNetId net, + const ClusterPinId pin, + t_pl_blocks_to_be_moved& blocks_affected, + double& delta_timing_cost) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + + const auto& connection_delay = g_placer_ctx.timing().connection_delay; + auto& connection_timing_cost = g_placer_ctx.mutable_timing().connection_timing_cost; + auto& proposed_connection_delay = g_placer_ctx.mutable_timing().proposed_connection_delay; + auto& proposed_connection_timing_cost = g_placer_ctx.mutable_timing().proposed_connection_timing_cost; + + if (cluster_ctx.clb_nlist.pin_type(pin) == PinType::DRIVER) { + /* This pin is a net driver on a moved block. */ + /* Recompute all point to point connection delays for the net sinks. */ + for (size_t ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net).size(); + ipin++) { + float temp_delay = comp_td_single_connection_delay(delay_model, net, + ipin); + /* If the delay hasn't changed, do not mark this pin as affected */ + if (temp_delay == connection_delay[net][ipin]) { + continue; + } + + /* Calculate proposed delay and cost values */ + proposed_connection_delay[net][ipin] = temp_delay; + + proposed_connection_timing_cost[net][ipin] = criticalities.criticality(net, ipin) * temp_delay; + delta_timing_cost += proposed_connection_timing_cost[net][ipin] + - connection_timing_cost[net][ipin]; + + /* Record this connection in blocks_affected.affected_pins */ + ClusterPinId sink_pin = cluster_ctx.clb_nlist.net_pin(net, ipin); + blocks_affected.affected_pins.push_back(sink_pin); + } + } else { + /* This pin is a net sink on a moved block */ + VTR_ASSERT_SAFE(cluster_ctx.clb_nlist.pin_type(pin) == PinType::SINK); + + /* Check if this sink's net is driven by a moved block */ + if (!driven_by_moved_block(net, blocks_affected)) { + /* Get the sink pin index in the net */ + int ipin = cluster_ctx.clb_nlist.pin_net_index(pin); + + float temp_delay = comp_td_single_connection_delay(delay_model, net, + ipin); + /* If the delay hasn't changed, do not mark this pin as affected */ + if (temp_delay == connection_delay[net][ipin]) { + return; + } + + /* Calculate proposed delay and cost values */ + proposed_connection_delay[net][ipin] = temp_delay; + + proposed_connection_timing_cost[net][ipin] = criticalities.criticality(net, ipin) * temp_delay; + delta_timing_cost += proposed_connection_timing_cost[net][ipin] + - connection_timing_cost[net][ipin]; + + /* Record this connection in blocks_affected.affected_pins */ + blocks_affected.affected_pins.push_back(pin); + } + } } /** @@ -1750,82 +1777,82 @@ static void update_td_delta_costs(const PlaceDelayModel *delay_model, * value suddenly got very good due to the block move, while a good slack value * got very bad, perhaps even worse than the original worse slack value. */ -static float analyze_setup_slack_cost(const PlacerSetupSlacks *setup_slacks) { - const auto &cluster_ctx = g_vpr_ctx.clustering(); - const auto &clb_nlist = cluster_ctx.clb_nlist; - - const auto &p_timing_ctx = g_placer_ctx.timing(); - const auto &connection_setup_slack = p_timing_ctx.connection_setup_slack; - - //Find the original/proposed setup slacks of pins with modified values - std::vector original_setup_slacks, proposed_setup_slacks; - - auto clb_pins_modified = setup_slacks->pins_with_modified_setup_slack(); - for (ClusterPinId clb_pin : clb_pins_modified) { - ClusterNetId net_id = clb_nlist.pin_net(clb_pin); - size_t ipin = clb_nlist.pin_net_index(clb_pin); - - original_setup_slacks.push_back(connection_setup_slack[net_id][ipin]); - proposed_setup_slacks.push_back( - setup_slacks->setup_slack(net_id, ipin)); - } - - //Sort in ascending order, from the worse slack value to the best - std::sort(original_setup_slacks.begin(), original_setup_slacks.end()); - std::sort(proposed_setup_slacks.begin(), proposed_setup_slacks.end()); - - //Check the first pair of slack values that are different - //If found, return their difference - for (size_t idiff = 0; idiff < original_setup_slacks.size(); ++idiff) { - float slack_diff = original_setup_slacks[idiff] - - proposed_setup_slacks[idiff]; - - if (slack_diff != 0) { - return slack_diff; - } - } - - //If all slack values are identical (or no modified slack values), - //reject this move by returning an arbitrary positive number as cost. - return 1; +static float analyze_setup_slack_cost(const PlacerSetupSlacks* setup_slacks) { + const auto& cluster_ctx = g_vpr_ctx.clustering(); + const auto& clb_nlist = cluster_ctx.clb_nlist; + + const auto& p_timing_ctx = g_placer_ctx.timing(); + const auto& connection_setup_slack = p_timing_ctx.connection_setup_slack; + + //Find the original/proposed setup slacks of pins with modified values + std::vector original_setup_slacks, proposed_setup_slacks; + + auto clb_pins_modified = setup_slacks->pins_with_modified_setup_slack(); + for (ClusterPinId clb_pin : clb_pins_modified) { + ClusterNetId net_id = clb_nlist.pin_net(clb_pin); + size_t ipin = clb_nlist.pin_net_index(clb_pin); + + original_setup_slacks.push_back(connection_setup_slack[net_id][ipin]); + proposed_setup_slacks.push_back( + setup_slacks->setup_slack(net_id, ipin)); + } + + //Sort in ascending order, from the worse slack value to the best + std::sort(original_setup_slacks.begin(), original_setup_slacks.end()); + std::sort(proposed_setup_slacks.begin(), proposed_setup_slacks.end()); + + //Check the first pair of slack values that are different + //If found, return their difference + for (size_t idiff = 0; idiff < original_setup_slacks.size(); ++idiff) { + float slack_diff = original_setup_slacks[idiff] + - proposed_setup_slacks[idiff]; + + if (slack_diff != 0) { + return slack_diff; + } + } + + //If all slack values are identical (or no modified slack values), + //reject this move by returning an arbitrary positive number as cost. + return 1; } static e_move_result assess_swap(double delta_c, double t) { - /* Returns: 1 -> move accepted, 0 -> rejected. */ - if (delta_c <= 0) { - return ACCEPTED; - } - - if (t == 0.) { - return REJECTED; - } - - float fnum = vtr::frand(); - float prob_fac = std::exp(-delta_c / t); - if (prob_fac > fnum) { - return ACCEPTED; - } - - return REJECTED; + /* Returns: 1 -> move accepted, 0 -> rejected. */ + if (delta_c <= 0) { + return ACCEPTED; + } + + if (t == 0.) { + return REJECTED; + } + + float fnum = vtr::frand(); + float prob_fac = std::exp(-delta_c / t); + if (prob_fac > fnum) { + return ACCEPTED; + } + + return REJECTED; } static double recompute_bb_cost() { - /* Recomputes the cost to eliminate roundoff that may have accrued. * - * This routine does as little work as possible to compute this new * - * cost. */ + /* Recomputes the cost to eliminate roundoff that may have accrued. * + * This routine does as little work as possible to compute this new * + * cost. */ - double cost = 0; + double cost = 0; - auto &cluster_ctx = g_vpr_ctx.clustering(); + auto& cluster_ctx = g_vpr_ctx.clustering(); - for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ - if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ - /* Bounding boxes don't have to be recomputed; they're correct. */ - cost += net_cost[net_id]; - } - } + for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ + if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ + /* Bounding boxes don't have to be recomputed; they're correct. */ + cost += net_cost[net_id]; + } + } - return (cost); + return (cost); } /** @@ -1835,37 +1862,34 @@ static double recompute_bb_cost() { * All the connections have already been gathered by blocks_affected.affected_pins * after running the routine find_affected_nets_and_update_costs() in try_swap(). */ -static void commit_td_cost(const t_pl_blocks_to_be_moved &blocks_affected) { - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &clb_nlist = cluster_ctx.clb_nlist; - - auto &p_timing_ctx = g_placer_ctx.mutable_timing(); - auto &connection_delay = p_timing_ctx.connection_delay; - auto &proposed_connection_delay = p_timing_ctx.proposed_connection_delay; - auto &connection_timing_cost = p_timing_ctx.connection_timing_cost; - auto &proposed_connection_timing_cost = - p_timing_ctx.proposed_connection_timing_cost; - - //Go through all the sink pins affected - for (ClusterPinId pin_id : blocks_affected.affected_pins) { - ClusterNetId net_id = clb_nlist.pin_net(pin_id); - int ipin = clb_nlist.pin_net_index(pin_id); - - //Commit the timing delay and cost values - connection_delay[net_id][ipin] = - proposed_connection_delay[net_id][ipin]; - proposed_connection_delay[net_id][ipin] = INVALID_DELAY; - connection_timing_cost[net_id][ipin] = - proposed_connection_timing_cost[net_id][ipin]; - proposed_connection_timing_cost[net_id][ipin] = INVALID_DELAY; - } +static void commit_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& clb_nlist = cluster_ctx.clb_nlist; + + auto& p_timing_ctx = g_placer_ctx.mutable_timing(); + auto& connection_delay = p_timing_ctx.connection_delay; + auto& proposed_connection_delay = p_timing_ctx.proposed_connection_delay; + auto& connection_timing_cost = p_timing_ctx.connection_timing_cost; + auto& proposed_connection_timing_cost = p_timing_ctx.proposed_connection_timing_cost; + + //Go through all the sink pins affected + for (ClusterPinId pin_id : blocks_affected.affected_pins) { + ClusterNetId net_id = clb_nlist.pin_net(pin_id); + int ipin = clb_nlist.pin_net_index(pin_id); + + //Commit the timing delay and cost values + connection_delay[net_id][ipin] = proposed_connection_delay[net_id][ipin]; + proposed_connection_delay[net_id][ipin] = INVALID_DELAY; + connection_timing_cost[net_id][ipin] = proposed_connection_timing_cost[net_id][ipin]; + proposed_connection_timing_cost[net_id][ipin] = INVALID_DELAY; + } } //Reverts modifications to proposed_connection_delay and proposed_connection_timing_cost based on //the move proposed in blocks_affected -static void revert_td_cost(const t_pl_blocks_to_be_moved &blocks_affected) { +static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { #ifndef VTR_ASSERT_SAFE_ENABLED - static_cast(blocks_affected); + static_cast(blocks_affected); #else //Invalidate temp delay & timing cost values to match sanity checks in //comp_td_connection_cost() @@ -1895,31 +1919,31 @@ static void revert_td_cost(const t_pl_blocks_to_be_moved &blocks_affected) { * the ClusteredPinTimingInvalidator class. */ static void invalidate_affected_connections( - const t_pl_blocks_to_be_moved &blocks_affected, - ClusteredPinTimingInvalidator *pin_tedges_invalidator, - TimingInfo *timing_info) { - VTR_ASSERT_SAFE(timing_info); - VTR_ASSERT_SAFE(pin_tedges_invalidator); - - /* Invalidate timing graph edges affected by the move */ - for (ClusterPinId pin : blocks_affected.affected_pins) { - pin_tedges_invalidator->invalidate_connection(pin, timing_info); - } + const t_pl_blocks_to_be_moved& blocks_affected, + ClusteredPinTimingInvalidator* pin_tedges_invalidator, + TimingInfo* timing_info) { + VTR_ASSERT_SAFE(timing_info); + VTR_ASSERT_SAFE(pin_tedges_invalidator); + + /* Invalidate timing graph edges affected by the move */ + for (ClusterPinId pin : blocks_affected.affected_pins) { + pin_tedges_invalidator->invalidate_connection(pin, timing_info); + } } //Returns true if 'net' is driven by one of the blocks in 'blocks_affected' static bool driven_by_moved_block(const ClusterNetId net, - const t_pl_blocks_to_be_moved &blocks_affected) { - auto &cluster_ctx = g_vpr_ctx.clustering(); - - ClusterBlockId net_driver_block = cluster_ctx.clb_nlist.net_driver_block( - net); - for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { - if (net_driver_block == blocks_affected.moved_blocks[iblk].block_num) { - return true; - } - } - return false; + const t_pl_blocks_to_be_moved& blocks_affected) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + + ClusterBlockId net_driver_block = cluster_ctx.clb_nlist.net_driver_block( + net); + for (int iblk = 0; iblk < blocks_affected.num_moved_blocks; iblk++) { + if (net_driver_block == blocks_affected.moved_blocks[iblk].block_num) { + return true; + } + } + return false; } /* Finds the cost from scratch. Done only when the placement * @@ -1931,324 +1955,321 @@ static bool driven_by_moved_block(const ClusterNetId net, * cost which can be used to check the correctness of the * * other routine. */ static double comp_bb_cost(e_cost_methods method) { - double cost = 0; - double expected_wirelength = 0.0; - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_move_ctx = g_placer_ctx.mutable_move(); - - for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ - if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ - /* Small nets don't use incremental updating on their bounding boxes, * - * so they can use a fast bounding box calculator. */ - if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET - && method == NORMAL) { - get_bb_from_scratch(net_id, &place_move_ctx.bb_coords[net_id], - &place_move_ctx.bb_num_on_edges[net_id]); - } else { - get_non_updateable_bb(net_id, - &place_move_ctx.bb_coords[net_id]); - } - - net_cost[net_id] = get_net_cost(net_id, - &place_move_ctx.bb_coords[net_id]); - cost += net_cost[net_id]; - if (method == CHECK) - expected_wirelength += get_net_wirelength_estimate(net_id, - &place_move_ctx.bb_coords[net_id]); - } - } - - if (method == CHECK) { - VTR_LOG("\n"); - VTR_LOG("BB estimate of min-dist (placement) wire length: %.0f\n", - expected_wirelength); - } - return cost; + double cost = 0; + double expected_wirelength = 0.0; + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_move_ctx = g_placer_ctx.mutable_move(); + + for (auto net_id : cluster_ctx.clb_nlist.nets()) { /* for each net ... */ + if (!cluster_ctx.clb_nlist.net_is_ignored(net_id)) { /* Do only if not ignored. */ + /* Small nets don't use incremental updating on their bounding boxes, * + * so they can use a fast bounding box calculator. */ + if (cluster_ctx.clb_nlist.net_sinks(net_id).size() >= SMALL_NET + && method == NORMAL) { + get_bb_from_scratch(net_id, &place_move_ctx.bb_coords[net_id], + &place_move_ctx.bb_num_on_edges[net_id]); + } else { + get_non_updateable_bb(net_id, + &place_move_ctx.bb_coords[net_id]); + } + + net_cost[net_id] = get_net_cost(net_id, + &place_move_ctx.bb_coords[net_id]); + cost += net_cost[net_id]; + if (method == CHECK) + expected_wirelength += get_net_wirelength_estimate(net_id, + &place_move_ctx.bb_coords[net_id]); + } + } + + if (method == CHECK) { + VTR_LOG("\n"); + VTR_LOG("BB estimate of min-dist (placement) wire length: %.0f\n", + expected_wirelength); + } + return cost; } /* Allocates the major structures needed only by the placer, primarily for * * computing costs quickly and such. */ static void alloc_and_load_placement_structs(float place_cost_exp, - const t_placer_opts &placer_opts, t_direct_inf *directs, - int num_directs) { - int max_pins_per_clb; - unsigned int ipin; + const t_placer_opts& placer_opts, + t_direct_inf* directs, + int num_directs) { + int max_pins_per_clb; + unsigned int ipin; - const auto &device_ctx = g_vpr_ctx.device(); - const auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_ctx = g_vpr_ctx.mutable_placement(); + const auto& device_ctx = g_vpr_ctx.device(); + const auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.mutable_placement(); - auto &p_timing_ctx = g_placer_ctx.mutable_timing(); - auto &place_move_ctx = g_placer_ctx.mutable_move(); + auto& p_timing_ctx = g_placer_ctx.mutable_timing(); + auto& place_move_ctx = g_placer_ctx.mutable_move(); - size_t num_nets = cluster_ctx.clb_nlist.nets().size(); + size_t num_nets = cluster_ctx.clb_nlist.nets().size(); - init_placement_context(); + init_placement_context(); - max_pins_per_clb = 0; - for (const auto &type : device_ctx.physical_tile_types) { - max_pins_per_clb = max(max_pins_per_clb, type.num_pins); - } + max_pins_per_clb = 0; + for (const auto& type : device_ctx.physical_tile_types) { + max_pins_per_clb = max(max_pins_per_clb, type.num_pins); + } - if (placer_opts.place_algorithm.is_timing_driven()) { - /* Allocate structures associated with timing driven placement */ - /* [0..cluster_ctx.clb_nlist.nets().size()-1][1..num_pins-1] */ + if (placer_opts.place_algorithm.is_timing_driven()) { + /* Allocate structures associated with timing driven placement */ + /* [0..cluster_ctx.clb_nlist.nets().size()-1][1..num_pins-1] */ - p_timing_ctx.connection_delay = make_net_pins_matrix( - cluster_ctx.clb_nlist, 0.f); - p_timing_ctx.proposed_connection_delay = make_net_pins_matrix( - cluster_ctx.clb_nlist, 0.f); + p_timing_ctx.connection_delay = make_net_pins_matrix( + cluster_ctx.clb_nlist, 0.f); + p_timing_ctx.proposed_connection_delay = make_net_pins_matrix( + cluster_ctx.clb_nlist, 0.f); - p_timing_ctx.connection_setup_slack = make_net_pins_matrix( - cluster_ctx.clb_nlist, std::numeric_limits::infinity()); + p_timing_ctx.connection_setup_slack = make_net_pins_matrix( + cluster_ctx.clb_nlist, std::numeric_limits::infinity()); - p_timing_ctx.connection_timing_cost = PlacerTimingCosts( - cluster_ctx.clb_nlist); - p_timing_ctx.proposed_connection_timing_cost = make_net_pins_matrix< - double>(cluster_ctx.clb_nlist, 0.); - p_timing_ctx.net_timing_cost.resize(num_nets, 0.); + p_timing_ctx.connection_timing_cost = PlacerTimingCosts( + cluster_ctx.clb_nlist); + p_timing_ctx.proposed_connection_timing_cost = make_net_pins_matrix< + double>(cluster_ctx.clb_nlist, 0.); + p_timing_ctx.net_timing_cost.resize(num_nets, 0.); - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - for (ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); - ipin++) { - p_timing_ctx.connection_delay[net_id][ipin] = 0; - p_timing_ctx.proposed_connection_delay[net_id][ipin] = - INVALID_DELAY; + for (auto net_id : cluster_ctx.clb_nlist.nets()) { + for (ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); + ipin++) { + p_timing_ctx.connection_delay[net_id][ipin] = 0; + p_timing_ctx.proposed_connection_delay[net_id][ipin] = INVALID_DELAY; - p_timing_ctx.proposed_connection_timing_cost[net_id][ipin] = - INVALID_DELAY; + p_timing_ctx.proposed_connection_timing_cost[net_id][ipin] = INVALID_DELAY; - if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) - continue; + if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) + continue; - p_timing_ctx.connection_timing_cost[net_id][ipin] = - INVALID_DELAY; - } - } - } + p_timing_ctx.connection_timing_cost[net_id][ipin] = INVALID_DELAY; + } + } + } - net_cost.resize(num_nets, -1.); - proposed_net_cost.resize(num_nets, -1.); - place_move_ctx.bb_coords.resize(num_nets, t_bb()); - place_move_ctx.bb_num_on_edges.resize(num_nets, t_bb()); + net_cost.resize(num_nets, -1.); + proposed_net_cost.resize(num_nets, -1.); + place_move_ctx.bb_coords.resize(num_nets, t_bb()); + place_move_ctx.bb_num_on_edges.resize(num_nets, t_bb()); - /* Used to store costs for moves not yet made and to indicate when a net's * - * cost has been recomputed. proposed_net_cost[inet] < 0 means net's cost hasn't * - * been recomputed. */ - bb_updated_before.resize(num_nets, NOT_UPDATED_YET); + /* Used to store costs for moves not yet made and to indicate when a net's * + * cost has been recomputed. proposed_net_cost[inet] < 0 means net's cost hasn't * + * been recomputed. */ + bb_updated_before.resize(num_nets, NOT_UPDATED_YET); - alloc_and_load_for_fast_cost_update(place_cost_exp); + alloc_and_load_for_fast_cost_update(place_cost_exp); - alloc_and_load_try_swap_structs(); + alloc_and_load_try_swap_structs(); - place_ctx.pl_macros = alloc_and_load_placement_macros(directs, num_directs); + place_ctx.pl_macros = alloc_and_load_placement_macros(directs, num_directs); } /* Frees the major structures needed by the placer (and not needed * * elsewhere). */ -static void free_placement_structs(const t_placer_opts &placer_opts) { - auto &place_move_ctx = g_placer_ctx.mutable_move(); - - if (placer_opts.place_algorithm.is_timing_driven()) { - auto &p_timing_ctx = g_placer_ctx.mutable_timing(); - - vtr::release_memory(p_timing_ctx.connection_timing_cost); - vtr::release_memory(p_timing_ctx.connection_delay); - vtr::release_memory(p_timing_ctx.connection_setup_slack); - vtr::release_memory(p_timing_ctx.proposed_connection_timing_cost); - vtr::release_memory(p_timing_ctx.proposed_connection_delay); - vtr::release_memory(p_timing_ctx.net_timing_cost); - } +static void free_placement_structs(const t_placer_opts& placer_opts) { + auto& place_move_ctx = g_placer_ctx.mutable_move(); + + if (placer_opts.place_algorithm.is_timing_driven()) { + auto& p_timing_ctx = g_placer_ctx.mutable_timing(); + + vtr::release_memory(p_timing_ctx.connection_timing_cost); + vtr::release_memory(p_timing_ctx.connection_delay); + vtr::release_memory(p_timing_ctx.connection_setup_slack); + vtr::release_memory(p_timing_ctx.proposed_connection_timing_cost); + vtr::release_memory(p_timing_ctx.proposed_connection_delay); + vtr::release_memory(p_timing_ctx.net_timing_cost); + } - free_placement_macros_structs(); + free_placement_macros_structs(); - vtr::release_memory(net_cost); - vtr::release_memory(proposed_net_cost); - vtr::release_memory(place_move_ctx.bb_coords); - vtr::release_memory(place_move_ctx.bb_num_on_edges); + vtr::release_memory(net_cost); + vtr::release_memory(proposed_net_cost); + vtr::release_memory(place_move_ctx.bb_coords); + vtr::release_memory(place_move_ctx.bb_num_on_edges); - vtr::release_memory(bb_updated_before); + vtr::release_memory(bb_updated_before); - free_fast_cost_update(); + free_fast_cost_update(); - free_try_swap_structs(); + free_try_swap_structs(); } static void alloc_and_load_try_swap_structs() { - /* Allocate the local bb_coordinate storage, etc. only once. */ - /* Allocate with size cluster_ctx.clb_nlist.nets().size() for any number of nets affected. */ - auto &cluster_ctx = g_vpr_ctx.clustering(); + /* Allocate the local bb_coordinate storage, etc. only once. */ + /* Allocate with size cluster_ctx.clb_nlist.nets().size() for any number of nets affected. */ + auto& cluster_ctx = g_vpr_ctx.clustering(); - size_t num_nets = cluster_ctx.clb_nlist.nets().size(); + size_t num_nets = cluster_ctx.clb_nlist.nets().size(); - ts_bb_coord_new.resize(num_nets, t_bb()); - ts_bb_edge_new.resize(num_nets, t_bb()); - ts_nets_to_update.resize(num_nets, ClusterNetId::INVALID()); + ts_bb_coord_new.resize(num_nets, t_bb()); + ts_bb_edge_new.resize(num_nets, t_bb()); + ts_nets_to_update.resize(num_nets, ClusterNetId::INVALID()); - auto &place_ctx = g_vpr_ctx.mutable_placement(); - place_ctx.compressed_block_grids = create_compressed_block_grids(); + auto& place_ctx = g_vpr_ctx.mutable_placement(); + place_ctx.compressed_block_grids = create_compressed_block_grids(); } static void free_try_swap_structs() { - vtr::release_memory(ts_bb_coord_new); - vtr::release_memory(ts_bb_edge_new); - vtr::release_memory(ts_nets_to_update); + vtr::release_memory(ts_bb_coord_new); + vtr::release_memory(ts_bb_edge_new); + vtr::release_memory(ts_nets_to_update); - auto &place_ctx = g_vpr_ctx.mutable_placement(); - vtr::release_memory(place_ctx.compressed_block_grids); + auto& place_ctx = g_vpr_ctx.mutable_placement(); + vtr::release_memory(place_ctx.compressed_block_grids); } /* This routine finds the bounding box of each net from scratch (i.e. * * from only the block location information). It updates both the * * coordinate and number of pins on each edge information. It * * should only be called when the bounding box information is not valid. */ -static void get_bb_from_scratch(ClusterNetId net_id, t_bb *coords, - t_bb *num_on_edges) { - int pnum, x, y, xmin, xmax, ymin, ymax; - int xmin_edge, xmax_edge, ymin_edge, ymax_edge; - - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_ctx = g_vpr_ctx.placement(); - auto &device_ctx = g_vpr_ctx.device(); - auto &grid = device_ctx.grid; - - ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); - pnum = net_pin_to_tile_pin_index(net_id, 0); - VTR_ASSERT(pnum >= 0); - x = place_ctx.block_locs[bnum].loc.x - + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y - + physical_tile_type(bnum)->pin_height_offset[pnum]; - - x = max(min(x, grid.width() - 2), 1); - y = max(min(y, grid.height() - 2), 1); - - xmin = x; - ymin = y; - xmax = x; - ymax = y; - xmin_edge = 1; - ymin_edge = 1; - xmax_edge = 1; - ymax_edge = 1; - - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - bnum = cluster_ctx.clb_nlist.pin_block(pin_id); - pnum = tile_pin_index(pin_id); - x = place_ctx.block_locs[bnum].loc.x - + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y - + physical_tile_type(bnum)->pin_height_offset[pnum]; - - /* Code below counts IO blocks as being within the 1..grid.width()-2, 1..grid.height()-2 clb array. * - * This is because channels do not go out of the 0..grid.width()-2, 0..grid.height()-2 range, and * - * I always take all channels impinging on the bounding box to be within * - * that bounding box. Hence, this "movement" of IO blocks does not affect * - * the which channels are included within the bounding box, and it * - * simplifies the code a lot. */ - - x = max(min(x, grid.width() - 2), 1); //-2 for no perim channels - y = max(min(y, grid.height() - 2), 1); //-2 for no perim channels - - if (x == xmin) { - xmin_edge++; - } - if (x == xmax) { /* Recall that xmin could equal xmax -- don't use else */ - xmax_edge++; - } else if (x < xmin) { - xmin = x; - xmin_edge = 1; - } else if (x > xmax) { - xmax = x; - xmax_edge = 1; - } - - if (y == ymin) { - ymin_edge++; - } - if (y == ymax) { - ymax_edge++; - } else if (y < ymin) { - ymin = y; - ymin_edge = 1; - } else if (y > ymax) { - ymax = y; - ymax_edge = 1; - } - } - - /* Copy the coordinates and number on edges information into the proper * - * structures. */ - coords->xmin = xmin; - coords->xmax = xmax; - coords->ymin = ymin; - coords->ymax = ymax; - - num_on_edges->xmin = xmin_edge; - num_on_edges->xmax = xmax_edge; - num_on_edges->ymin = ymin_edge; - num_on_edges->ymax = ymax_edge; +static void get_bb_from_scratch(ClusterNetId net_id, t_bb* coords, t_bb* num_on_edges) { + int pnum, x, y, xmin, xmax, ymin, ymax; + int xmin_edge, xmax_edge, ymin_edge, ymax_edge; + + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + auto& device_ctx = g_vpr_ctx.device(); + auto& grid = device_ctx.grid; + + ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); + pnum = net_pin_to_tile_pin_index(net_id, 0); + VTR_ASSERT(pnum >= 0); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + x = max(min(x, grid.width() - 2), 1); + y = max(min(y, grid.height() - 2), 1); + + xmin = x; + ymin = y; + xmax = x; + ymax = y; + xmin_edge = 1; + ymin_edge = 1; + xmax_edge = 1; + ymax_edge = 1; + + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + bnum = cluster_ctx.clb_nlist.pin_block(pin_id); + pnum = tile_pin_index(pin_id); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + /* Code below counts IO blocks as being within the 1..grid.width()-2, 1..grid.height()-2 clb array. * + * This is because channels do not go out of the 0..grid.width()-2, 0..grid.height()-2 range, and * + * I always take all channels impinging on the bounding box to be within * + * that bounding box. Hence, this "movement" of IO blocks does not affect * + * the which channels are included within the bounding box, and it * + * simplifies the code a lot. */ + + x = max(min(x, grid.width() - 2), 1); //-2 for no perim channels + y = max(min(y, grid.height() - 2), 1); //-2 for no perim channels + + if (x == xmin) { + xmin_edge++; + } + if (x == xmax) { /* Recall that xmin could equal xmax -- don't use else */ + xmax_edge++; + } else if (x < xmin) { + xmin = x; + xmin_edge = 1; + } else if (x > xmax) { + xmax = x; + xmax_edge = 1; + } + + if (y == ymin) { + ymin_edge++; + } + if (y == ymax) { + ymax_edge++; + } else if (y < ymin) { + ymin = y; + ymin_edge = 1; + } else if (y > ymax) { + ymax = y; + ymax_edge = 1; + } + } + + /* Copy the coordinates and number on edges information into the proper * + * structures. */ + coords->xmin = xmin; + coords->xmax = xmax; + coords->ymin = ymin; + coords->ymax = ymax; + + num_on_edges->xmin = xmin_edge; + num_on_edges->xmax = xmax_edge; + num_on_edges->ymin = ymin_edge; + num_on_edges->ymax = ymax_edge; } static double wirelength_crossing_count(size_t fanout) { - /* Get the expected "crossing count" of a net, based on its number * - * of pins. Extrapolate for very large nets. */ - - if (fanout > 50) { - return 2.7933 + 0.02616 * (fanout - 50); - } else { - return cross_count[fanout - 1]; - } + /* Get the expected "crossing count" of a net, based on its number * + * of pins. Extrapolate for very large nets. */ + + if (fanout > 50) { + return 2.7933 + 0.02616 * (fanout - 50); + } else { + return cross_count[fanout - 1]; + } } -static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb *bbptr) { - /* WMF: Finds the estimate of wirelength due to one net by looking at * - * its coordinate bounding box. */ +static double get_net_wirelength_estimate(ClusterNetId net_id, t_bb* bbptr) { + /* WMF: Finds the estimate of wirelength due to one net by looking at * + * its coordinate bounding box. */ - double ncost, crossing; - auto &cluster_ctx = g_vpr_ctx.clustering(); + double ncost, crossing; + auto& cluster_ctx = g_vpr_ctx.clustering(); - crossing = wirelength_crossing_count( - cluster_ctx.clb_nlist.net_pins(net_id).size()); + crossing = wirelength_crossing_count( + cluster_ctx.clb_nlist.net_pins(net_id).size()); - /* Could insert a check for xmin == xmax. In that case, assume * - * connection will be made with no bends and hence no x-cost. * - * Same thing for y-cost. */ + /* Could insert a check for xmin == xmax. In that case, assume * + * connection will be made with no bends and hence no x-cost. * + * Same thing for y-cost. */ - /* Cost = wire length along channel * cross_count / average * - * channel capacity. Do this for x, then y direction and add. */ + /* Cost = wire length along channel * cross_count / average * + * channel capacity. Do this for x, then y direction and add. */ - ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing; + ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing; - ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing; + ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing; - return (ncost); + return (ncost); } -static double get_net_cost(ClusterNetId net_id, t_bb *bbptr) { - /* Finds the cost due to one net by looking at its coordinate bounding * - * box. */ +static double get_net_cost(ClusterNetId net_id, t_bb* bbptr) { + /* Finds the cost due to one net by looking at its coordinate bounding * + * box. */ - double ncost, crossing; - auto &cluster_ctx = g_vpr_ctx.clustering(); + double ncost, crossing; + auto& cluster_ctx = g_vpr_ctx.clustering(); - crossing = wirelength_crossing_count( - cluster_ctx.clb_nlist.net_pins(net_id).size()); + crossing = wirelength_crossing_count( + cluster_ctx.clb_nlist.net_pins(net_id).size()); - /* Could insert a check for xmin == xmax. In that case, assume * - * connection will be made with no bends and hence no x-cost. * - * Same thing for y-cost. */ + /* Could insert a check for xmin == xmax. In that case, assume * + * connection will be made with no bends and hence no x-cost. * + * Same thing for y-cost. */ - /* Cost = wire length along channel * cross_count / average * - * channel capacity. Do this for x, then y direction and add. */ + /* Cost = wire length along channel * cross_count / average * + * channel capacity. Do this for x, then y direction and add. */ - ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing - * chanx_place_cost_fac[bbptr->ymax][bbptr->ymin - 1]; + ncost = (bbptr->xmax - bbptr->xmin + 1) * crossing + * chanx_place_cost_fac[bbptr->ymax][bbptr->ymin - 1]; - ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing - * chany_place_cost_fac[bbptr->xmax][bbptr->xmin - 1]; + ncost += (bbptr->ymax - bbptr->ymin + 1) * crossing + * chany_place_cost_fac[bbptr->xmax][bbptr->xmin - 1]; - return (ncost); + return (ncost); } /* Finds the bounding box of a net and stores its coordinates in the * @@ -2258,439 +2279,438 @@ static double get_net_cost(ClusterNetId net_id, t_bb *bbptr) { * Currently assumes channels on both sides of the CLBs forming the * * edges of the bounding box can be used. Essentially, I am assuming * * the pins always lie on the outside of the bounding box. */ -static void get_non_updateable_bb(ClusterNetId net_id, t_bb *bb_coord_new) { - //TODO: account for multiple physical pin instances per logical pin - - int xmax, ymax, xmin, ymin, x, y; - int pnum; - - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &place_ctx = g_vpr_ctx.placement(); - auto &device_ctx = g_vpr_ctx.device(); - - ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); - pnum = net_pin_to_tile_pin_index(net_id, 0); - x = place_ctx.block_locs[bnum].loc.x - + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y - + physical_tile_type(bnum)->pin_height_offset[pnum]; - - xmin = x; - ymin = y; - xmax = x; - ymax = y; - - for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { - bnum = cluster_ctx.clb_nlist.pin_block(pin_id); - pnum = tile_pin_index(pin_id); - x = place_ctx.block_locs[bnum].loc.x - + physical_tile_type(bnum)->pin_width_offset[pnum]; - y = place_ctx.block_locs[bnum].loc.y - + physical_tile_type(bnum)->pin_height_offset[pnum]; - - if (x < xmin) { - xmin = x; - } else if (x > xmax) { - xmax = x; - } - - if (y < ymin) { - ymin = y; - } else if (y > ymax) { - ymax = y; - } - } - - /* Now I've found the coordinates of the bounding box. There are no * - * channels beyond device_ctx.grid.width()-2 and * - * device_ctx.grid.height() - 2, so I want to clip to that. As well,* - * since I'll always include the channel immediately below and the * - * channel immediately to the left of the bounding box, I want to * - * clip to 1 in both directions as well (since minimum channel index * - * is 0). See route_common.cpp for a channel diagram. */ - - bb_coord_new->xmin = max(min(xmin, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - bb_coord_new->ymin = max(min(ymin, device_ctx.grid.height() - 2), 1); //-2 for no perim channels - bb_coord_new->xmax = max(min(xmax, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - bb_coord_new->ymax = max(min(ymax, device_ctx.grid.height() - 2), 1); //-2 for no perim channels +static void get_non_updateable_bb(ClusterNetId net_id, t_bb* bb_coord_new) { + //TODO: account for multiple physical pin instances per logical pin + + int xmax, ymax, xmin, ymin, x, y; + int pnum; + + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + auto& device_ctx = g_vpr_ctx.device(); + + ClusterBlockId bnum = cluster_ctx.clb_nlist.net_driver_block(net_id); + pnum = net_pin_to_tile_pin_index(net_id, 0); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + xmin = x; + ymin = y; + xmax = x; + ymax = y; + + for (auto pin_id : cluster_ctx.clb_nlist.net_sinks(net_id)) { + bnum = cluster_ctx.clb_nlist.pin_block(pin_id); + pnum = tile_pin_index(pin_id); + x = place_ctx.block_locs[bnum].loc.x + + physical_tile_type(bnum)->pin_width_offset[pnum]; + y = place_ctx.block_locs[bnum].loc.y + + physical_tile_type(bnum)->pin_height_offset[pnum]; + + if (x < xmin) { + xmin = x; + } else if (x > xmax) { + xmax = x; + } + + if (y < ymin) { + ymin = y; + } else if (y > ymax) { + ymax = y; + } + } + + /* Now I've found the coordinates of the bounding box. There are no * + * channels beyond device_ctx.grid.width()-2 and * + * device_ctx.grid.height() - 2, so I want to clip to that. As well,* + * since I'll always include the channel immediately below and the * + * channel immediately to the left of the bounding box, I want to * + * clip to 1 in both directions as well (since minimum channel index * + * is 0). See route_common.cpp for a channel diagram. */ + + bb_coord_new->xmin = max(min(xmin, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + bb_coord_new->ymin = max(min(ymin, device_ctx.grid.height() - 2), 1); //-2 for no perim channels + bb_coord_new->xmax = max(min(xmax, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + bb_coord_new->ymax = max(min(ymax, device_ctx.grid.height() - 2), 1); //-2 for no perim channels } -static void update_bb(ClusterNetId net_id, t_bb *bb_coord_new, - t_bb *bb_edge_new, int xold, int yold, int xnew, int ynew) { - /* Updates the bounding box of a net by storing its coordinates in * - * the bb_coord_new data structure and the number of blocks on each * - * edge in the bb_edge_new data structure. This routine should only * - * be called for large nets, since it has some overhead relative to * - * just doing a brute force bounding box calculation. The bounding * - * box coordinate and edge information for inet must be valid before * - * this routine is called. * - * Currently assumes channels on both sides of the CLBs forming the * - * edges of the bounding box can be used. Essentially, I am assuming * - * the pins always lie on the outside of the bounding box. * - * The x and y coordinates are the pin's x and y coordinates. */ - /* IO blocks are considered to be one cell in for simplicity. */ - //TODO: account for multiple physical pin instances per logical pin - const t_bb *curr_bb_edge, *curr_bb_coord; - - auto &device_ctx = g_vpr_ctx.device(); - auto &place_move_ctx = g_placer_ctx.move(); - - xnew = max(min(xnew, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - ynew = max(min(ynew, device_ctx.grid.height() - 2), 1); //-2 for no perim channels - xold = max(min(xold, device_ctx.grid.width() - 2), 1); //-2 for no perim channels - yold = max(min(yold, device_ctx.grid.height() - 2), 1); //-2 for no perim channels - - /* Check if the net had been updated before. */ - if (bb_updated_before[net_id] == GOT_FROM_SCRATCH) { - /* The net had been updated from scratch, DO NOT update again! */ - return; - } else if (bb_updated_before[net_id] == NOT_UPDATED_YET) { - /* The net had NOT been updated before, could use the old values */ - curr_bb_coord = &place_move_ctx.bb_coords[net_id]; - curr_bb_edge = &place_move_ctx.bb_num_on_edges[net_id]; - bb_updated_before[net_id] = UPDATED_ONCE; - } else { - /* The net had been updated before, must use the new values */ - curr_bb_coord = bb_coord_new; - curr_bb_edge = bb_edge_new; - } - - /* Check if I can update the bounding box incrementally. */ - - if (xnew < xold) { /* Move to left. */ - - /* Update the xmax fields for coordinates and number of edges first. */ - - if (xold == curr_bb_coord->xmax) { /* Old position at xmax. */ - if (curr_bb_edge->xmax == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->xmax = curr_bb_edge->xmax - 1; - bb_coord_new->xmax = curr_bb_coord->xmax; - } - } else { /* Move to left, old postion was not at xmax. */ - bb_coord_new->xmax = curr_bb_coord->xmax; - bb_edge_new->xmax = curr_bb_edge->xmax; - } - - /* Now do the xmin fields for coordinates and number of edges. */ - - if (xnew < curr_bb_coord->xmin) { /* Moved past xmin */ - bb_coord_new->xmin = xnew; - bb_edge_new->xmin = 1; - } else if (xnew == curr_bb_coord->xmin) { /* Moved to xmin */ - bb_coord_new->xmin = xnew; - bb_edge_new->xmin = curr_bb_edge->xmin + 1; - } else { /* Xmin unchanged. */ - bb_coord_new->xmin = curr_bb_coord->xmin; - bb_edge_new->xmin = curr_bb_edge->xmin; - } - /* End of move to left case. */ - - } else if (xnew > xold) { /* Move to right. */ - - /* Update the xmin fields for coordinates and number of edges first. */ - - if (xold == curr_bb_coord->xmin) { /* Old position at xmin. */ - if (curr_bb_edge->xmin == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->xmin = curr_bb_edge->xmin - 1; - bb_coord_new->xmin = curr_bb_coord->xmin; - } - } else { /* Move to right, old position was not at xmin. */ - bb_coord_new->xmin = curr_bb_coord->xmin; - bb_edge_new->xmin = curr_bb_edge->xmin; - } - - /* Now do the xmax fields for coordinates and number of edges. */ - - if (xnew > curr_bb_coord->xmax) { /* Moved past xmax. */ - bb_coord_new->xmax = xnew; - bb_edge_new->xmax = 1; - } else if (xnew == curr_bb_coord->xmax) { /* Moved to xmax */ - bb_coord_new->xmax = xnew; - bb_edge_new->xmax = curr_bb_edge->xmax + 1; - } else { /* Xmax unchanged. */ - bb_coord_new->xmax = curr_bb_coord->xmax; - bb_edge_new->xmax = curr_bb_edge->xmax; - } - /* End of move to right case. */ - - } else { /* xnew == xold -- no x motion. */ - bb_coord_new->xmin = curr_bb_coord->xmin; - bb_coord_new->xmax = curr_bb_coord->xmax; - bb_edge_new->xmin = curr_bb_edge->xmin; - bb_edge_new->xmax = curr_bb_edge->xmax; - } - - /* Now account for the y-direction motion. */ - - if (ynew < yold) { /* Move down. */ - - /* Update the ymax fields for coordinates and number of edges first. */ - - if (yold == curr_bb_coord->ymax) { /* Old position at ymax. */ - if (curr_bb_edge->ymax == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->ymax = curr_bb_edge->ymax - 1; - bb_coord_new->ymax = curr_bb_coord->ymax; - } - } else { /* Move down, old postion was not at ymax. */ - bb_coord_new->ymax = curr_bb_coord->ymax; - bb_edge_new->ymax = curr_bb_edge->ymax; - } - - /* Now do the ymin fields for coordinates and number of edges. */ - - if (ynew < curr_bb_coord->ymin) { /* Moved past ymin */ - bb_coord_new->ymin = ynew; - bb_edge_new->ymin = 1; - } else if (ynew == curr_bb_coord->ymin) { /* Moved to ymin */ - bb_coord_new->ymin = ynew; - bb_edge_new->ymin = curr_bb_edge->ymin + 1; - } else { /* ymin unchanged. */ - bb_coord_new->ymin = curr_bb_coord->ymin; - bb_edge_new->ymin = curr_bb_edge->ymin; - } - /* End of move down case. */ - - } else if (ynew > yold) { /* Moved up. */ - - /* Update the ymin fields for coordinates and number of edges first. */ - - if (yold == curr_bb_coord->ymin) { /* Old position at ymin. */ - if (curr_bb_edge->ymin == 1) { - get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); - bb_updated_before[net_id] = GOT_FROM_SCRATCH; - return; - } else { - bb_edge_new->ymin = curr_bb_edge->ymin - 1; - bb_coord_new->ymin = curr_bb_coord->ymin; - } - } else { /* Moved up, old position was not at ymin. */ - bb_coord_new->ymin = curr_bb_coord->ymin; - bb_edge_new->ymin = curr_bb_edge->ymin; - } - - /* Now do the ymax fields for coordinates and number of edges. */ - - if (ynew > curr_bb_coord->ymax) { /* Moved past ymax. */ - bb_coord_new->ymax = ynew; - bb_edge_new->ymax = 1; - } else if (ynew == curr_bb_coord->ymax) { /* Moved to ymax */ - bb_coord_new->ymax = ynew; - bb_edge_new->ymax = curr_bb_edge->ymax + 1; - } else { /* ymax unchanged. */ - bb_coord_new->ymax = curr_bb_coord->ymax; - bb_edge_new->ymax = curr_bb_edge->ymax; - } - /* End of move up case. */ - - } else { /* ynew == yold -- no y motion. */ - bb_coord_new->ymin = curr_bb_coord->ymin; - bb_coord_new->ymax = curr_bb_coord->ymax; - bb_edge_new->ymin = curr_bb_edge->ymin; - bb_edge_new->ymax = curr_bb_edge->ymax; - } - - if (bb_updated_before[net_id] == NOT_UPDATED_YET) { - bb_updated_before[net_id] = UPDATED_ONCE; - } +static void update_bb(ClusterNetId net_id, t_bb* bb_coord_new, t_bb* bb_edge_new, int xold, int yold, int xnew, int ynew) { + /* Updates the bounding box of a net by storing its coordinates in * + * the bb_coord_new data structure and the number of blocks on each * + * edge in the bb_edge_new data structure. This routine should only * + * be called for large nets, since it has some overhead relative to * + * just doing a brute force bounding box calculation. The bounding * + * box coordinate and edge information for inet must be valid before * + * this routine is called. * + * Currently assumes channels on both sides of the CLBs forming the * + * edges of the bounding box can be used. Essentially, I am assuming * + * the pins always lie on the outside of the bounding box. * + * The x and y coordinates are the pin's x and y coordinates. */ + /* IO blocks are considered to be one cell in for simplicity. */ + //TODO: account for multiple physical pin instances per logical pin + const t_bb *curr_bb_edge, *curr_bb_coord; + + auto& device_ctx = g_vpr_ctx.device(); + auto& place_move_ctx = g_placer_ctx.move(); + + xnew = max(min(xnew, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + ynew = max(min(ynew, device_ctx.grid.height() - 2), 1); //-2 for no perim channels + xold = max(min(xold, device_ctx.grid.width() - 2), 1); //-2 for no perim channels + yold = max(min(yold, device_ctx.grid.height() - 2), 1); //-2 for no perim channels + + /* Check if the net had been updated before. */ + if (bb_updated_before[net_id] == GOT_FROM_SCRATCH) { + /* The net had been updated from scratch, DO NOT update again! */ + return; + } else if (bb_updated_before[net_id] == NOT_UPDATED_YET) { + /* The net had NOT been updated before, could use the old values */ + curr_bb_coord = &place_move_ctx.bb_coords[net_id]; + curr_bb_edge = &place_move_ctx.bb_num_on_edges[net_id]; + bb_updated_before[net_id] = UPDATED_ONCE; + } else { + /* The net had been updated before, must use the new values */ + curr_bb_coord = bb_coord_new; + curr_bb_edge = bb_edge_new; + } + + /* Check if I can update the bounding box incrementally. */ + + if (xnew < xold) { /* Move to left. */ + + /* Update the xmax fields for coordinates and number of edges first. */ + + if (xold == curr_bb_coord->xmax) { /* Old position at xmax. */ + if (curr_bb_edge->xmax == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->xmax = curr_bb_edge->xmax - 1; + bb_coord_new->xmax = curr_bb_coord->xmax; + } + } else { /* Move to left, old postion was not at xmax. */ + bb_coord_new->xmax = curr_bb_coord->xmax; + bb_edge_new->xmax = curr_bb_edge->xmax; + } + + /* Now do the xmin fields for coordinates and number of edges. */ + + if (xnew < curr_bb_coord->xmin) { /* Moved past xmin */ + bb_coord_new->xmin = xnew; + bb_edge_new->xmin = 1; + } else if (xnew == curr_bb_coord->xmin) { /* Moved to xmin */ + bb_coord_new->xmin = xnew; + bb_edge_new->xmin = curr_bb_edge->xmin + 1; + } else { /* Xmin unchanged. */ + bb_coord_new->xmin = curr_bb_coord->xmin; + bb_edge_new->xmin = curr_bb_edge->xmin; + } + /* End of move to left case. */ + + } else if (xnew > xold) { /* Move to right. */ + + /* Update the xmin fields for coordinates and number of edges first. */ + + if (xold == curr_bb_coord->xmin) { /* Old position at xmin. */ + if (curr_bb_edge->xmin == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->xmin = curr_bb_edge->xmin - 1; + bb_coord_new->xmin = curr_bb_coord->xmin; + } + } else { /* Move to right, old position was not at xmin. */ + bb_coord_new->xmin = curr_bb_coord->xmin; + bb_edge_new->xmin = curr_bb_edge->xmin; + } + + /* Now do the xmax fields for coordinates and number of edges. */ + + if (xnew > curr_bb_coord->xmax) { /* Moved past xmax. */ + bb_coord_new->xmax = xnew; + bb_edge_new->xmax = 1; + } else if (xnew == curr_bb_coord->xmax) { /* Moved to xmax */ + bb_coord_new->xmax = xnew; + bb_edge_new->xmax = curr_bb_edge->xmax + 1; + } else { /* Xmax unchanged. */ + bb_coord_new->xmax = curr_bb_coord->xmax; + bb_edge_new->xmax = curr_bb_edge->xmax; + } + /* End of move to right case. */ + + } else { /* xnew == xold -- no x motion. */ + bb_coord_new->xmin = curr_bb_coord->xmin; + bb_coord_new->xmax = curr_bb_coord->xmax; + bb_edge_new->xmin = curr_bb_edge->xmin; + bb_edge_new->xmax = curr_bb_edge->xmax; + } + + /* Now account for the y-direction motion. */ + + if (ynew < yold) { /* Move down. */ + + /* Update the ymax fields for coordinates and number of edges first. */ + + if (yold == curr_bb_coord->ymax) { /* Old position at ymax. */ + if (curr_bb_edge->ymax == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->ymax = curr_bb_edge->ymax - 1; + bb_coord_new->ymax = curr_bb_coord->ymax; + } + } else { /* Move down, old postion was not at ymax. */ + bb_coord_new->ymax = curr_bb_coord->ymax; + bb_edge_new->ymax = curr_bb_edge->ymax; + } + + /* Now do the ymin fields for coordinates and number of edges. */ + + if (ynew < curr_bb_coord->ymin) { /* Moved past ymin */ + bb_coord_new->ymin = ynew; + bb_edge_new->ymin = 1; + } else if (ynew == curr_bb_coord->ymin) { /* Moved to ymin */ + bb_coord_new->ymin = ynew; + bb_edge_new->ymin = curr_bb_edge->ymin + 1; + } else { /* ymin unchanged. */ + bb_coord_new->ymin = curr_bb_coord->ymin; + bb_edge_new->ymin = curr_bb_edge->ymin; + } + /* End of move down case. */ + + } else if (ynew > yold) { /* Moved up. */ + + /* Update the ymin fields for coordinates and number of edges first. */ + + if (yold == curr_bb_coord->ymin) { /* Old position at ymin. */ + if (curr_bb_edge->ymin == 1) { + get_bb_from_scratch(net_id, bb_coord_new, bb_edge_new); + bb_updated_before[net_id] = GOT_FROM_SCRATCH; + return; + } else { + bb_edge_new->ymin = curr_bb_edge->ymin - 1; + bb_coord_new->ymin = curr_bb_coord->ymin; + } + } else { /* Moved up, old position was not at ymin. */ + bb_coord_new->ymin = curr_bb_coord->ymin; + bb_edge_new->ymin = curr_bb_edge->ymin; + } + + /* Now do the ymax fields for coordinates and number of edges. */ + + if (ynew > curr_bb_coord->ymax) { /* Moved past ymax. */ + bb_coord_new->ymax = ynew; + bb_edge_new->ymax = 1; + } else if (ynew == curr_bb_coord->ymax) { /* Moved to ymax */ + bb_coord_new->ymax = ynew; + bb_edge_new->ymax = curr_bb_edge->ymax + 1; + } else { /* ymax unchanged. */ + bb_coord_new->ymax = curr_bb_coord->ymax; + bb_edge_new->ymax = curr_bb_edge->ymax; + } + /* End of move up case. */ + + } else { /* ynew == yold -- no y motion. */ + bb_coord_new->ymin = curr_bb_coord->ymin; + bb_coord_new->ymax = curr_bb_coord->ymax; + bb_edge_new->ymin = curr_bb_edge->ymin; + bb_edge_new->ymax = curr_bb_edge->ymax; + } + + if (bb_updated_before[net_id] == NOT_UPDATED_YET) { + bb_updated_before[net_id] = UPDATED_ONCE; + } } static void free_fast_cost_update() { - auto &device_ctx = g_vpr_ctx.device(); - - for (size_t i = 0; i < device_ctx.grid.height(); i++) { - free(chanx_place_cost_fac[i]); - } - free(chanx_place_cost_fac); - chanx_place_cost_fac = nullptr; - - for (size_t i = 0; i < device_ctx.grid.width(); i++) { - free(chany_place_cost_fac[i]); - } - free(chany_place_cost_fac); - chany_place_cost_fac = nullptr; + auto& device_ctx = g_vpr_ctx.device(); + + for (size_t i = 0; i < device_ctx.grid.height(); i++) { + free(chanx_place_cost_fac[i]); + } + free(chanx_place_cost_fac); + chanx_place_cost_fac = nullptr; + + for (size_t i = 0; i < device_ctx.grid.width(); i++) { + free(chany_place_cost_fac[i]); + } + free(chany_place_cost_fac); + chany_place_cost_fac = nullptr; } static void alloc_and_load_for_fast_cost_update(float place_cost_exp) { - /* Allocates and loads the chanx_place_cost_fac and chany_place_cost_fac * - * arrays with the inverse of the average number of tracks per channel * - * between [subhigh] and [sublow]. This is only useful for the cost * - * function that takes the length of the net bounding box in each * - * dimension divided by the average number of tracks in that direction. * - * For other cost functions, you don't have to bother calling this * - * routine; when using the cost function described above, however, you * - * must always call this routine after you call init_chan and before * - * you do any placement cost determination. The place_cost_exp factor * - * specifies to what power the width of the channel should be taken -- * - * larger numbers make narrower channels more expensive. */ - - auto &device_ctx = g_vpr_ctx.device(); - - /* Access arrays below as chan?_place_cost_fac[subhigh][sublow]. Since * - * subhigh must be greater than or equal to sublow, we only need to * - * allocate storage for the lower half of a matrix. */ - - chanx_place_cost_fac = (float**) vtr::malloc( - (device_ctx.grid.height()) * sizeof(float*)); - for (size_t i = 0; i < device_ctx.grid.height(); i++) - chanx_place_cost_fac[i] = (float*) vtr::malloc((i + 1) * sizeof(float)); - - chany_place_cost_fac = (float**) vtr::malloc( - (device_ctx.grid.width() + 1) * sizeof(float*)); - for (size_t i = 0; i < device_ctx.grid.width(); i++) - chany_place_cost_fac[i] = (float*) vtr::malloc((i + 1) * sizeof(float)); - - /* First compute the number of tracks between channel high and channel * - * low, inclusive, in an efficient manner. */ - - chanx_place_cost_fac[0][0] = device_ctx.chan_width.x_list[0]; - - for (size_t high = 1; high < device_ctx.grid.height(); high++) { - chanx_place_cost_fac[high][high] = device_ctx.chan_width.x_list[high]; - for (size_t low = 0; low < high; low++) { - chanx_place_cost_fac[high][low] = - chanx_place_cost_fac[high - 1][low] - + device_ctx.chan_width.x_list[high]; - } - } - - /* Now compute the inverse of the average number of tracks per channel * - * between high and low. The cost function divides by the average * - * number of tracks per channel, so by storing the inverse I convert * - * this to a faster multiplication. Take this final number to the * - * place_cost_exp power -- numbers other than one mean this is no * - * longer a simple "average number of tracks"; it is some power of * - * that, allowing greater penalization of narrow channels. */ - - for (size_t high = 0; high < device_ctx.grid.height(); high++) - for (size_t low = 0; low <= high; low++) { - /* Since we will divide the wiring cost by the average channel * - * capacity between high and low, having only 0 width channels * - * will result in infinite wiring capacity normalization * - * factor, and extremely bad placer behaviour. Hence we change * - * this to a small (1 track) channel capacity instead. */ - if (chanx_place_cost_fac[high][low] == 0.0f) { - VTR_LOG_WARN("CHANX place cost fac is 0 at %d %d\n", high, low); - chanx_place_cost_fac[high][low] = 1.0f; - } - - chanx_place_cost_fac[high][low] = (high - low + 1.) - / chanx_place_cost_fac[high][low]; - chanx_place_cost_fac[high][low] = pow( - (double) chanx_place_cost_fac[high][low], - (double) place_cost_exp); - } - - /* Now do the same thing for the y-directed channels. First get the * - * number of tracks between channel high and channel low, inclusive. */ - - chany_place_cost_fac[0][0] = device_ctx.chan_width.y_list[0]; - - for (size_t high = 1; high < device_ctx.grid.width(); high++) { - chany_place_cost_fac[high][high] = device_ctx.chan_width.y_list[high]; - for (size_t low = 0; low < high; low++) { - chany_place_cost_fac[high][low] = - chany_place_cost_fac[high - 1][low] - + device_ctx.chan_width.y_list[high]; - } - } - - /* Now compute the inverse of the average number of tracks per channel * - * between high and low. Take to specified power. */ - - for (size_t high = 0; high < device_ctx.grid.width(); high++) - for (size_t low = 0; low <= high; low++) { - /* Since we will divide the wiring cost by the average channel * - * capacity between high and low, having only 0 width channels * - * will result in infinite wiring capacity normalization * - * factor, and extremely bad placer behaviour. Hence we change * - * this to a small (1 track) channel capacity instead. */ - if (chany_place_cost_fac[high][low] == 0.0f) { - VTR_LOG_WARN("CHANY place cost fac is 0 at %d %d\n", high, low); - chany_place_cost_fac[high][low] = 1.0f; - } - - chany_place_cost_fac[high][low] = (high - low + 1.) - / chany_place_cost_fac[high][low]; - chany_place_cost_fac[high][low] = pow( - (double) chany_place_cost_fac[high][low], - (double) place_cost_exp); - } + /* Allocates and loads the chanx_place_cost_fac and chany_place_cost_fac * + * arrays with the inverse of the average number of tracks per channel * + * between [subhigh] and [sublow]. This is only useful for the cost * + * function that takes the length of the net bounding box in each * + * dimension divided by the average number of tracks in that direction. * + * For other cost functions, you don't have to bother calling this * + * routine; when using the cost function described above, however, you * + * must always call this routine after you call init_chan and before * + * you do any placement cost determination. The place_cost_exp factor * + * specifies to what power the width of the channel should be taken -- * + * larger numbers make narrower channels more expensive. */ + + auto& device_ctx = g_vpr_ctx.device(); + + /* Access arrays below as chan?_place_cost_fac[subhigh][sublow]. Since * + * subhigh must be greater than or equal to sublow, we only need to * + * allocate storage for the lower half of a matrix. */ + + chanx_place_cost_fac = (float**)vtr::malloc( + (device_ctx.grid.height()) * sizeof(float*)); + for (size_t i = 0; i < device_ctx.grid.height(); i++) + chanx_place_cost_fac[i] = (float*)vtr::malloc((i + 1) * sizeof(float)); + + chany_place_cost_fac = (float**)vtr::malloc( + (device_ctx.grid.width() + 1) * sizeof(float*)); + for (size_t i = 0; i < device_ctx.grid.width(); i++) + chany_place_cost_fac[i] = (float*)vtr::malloc((i + 1) * sizeof(float)); + + /* First compute the number of tracks between channel high and channel * + * low, inclusive, in an efficient manner. */ + + chanx_place_cost_fac[0][0] = device_ctx.chan_width.x_list[0]; + + for (size_t high = 1; high < device_ctx.grid.height(); high++) { + chanx_place_cost_fac[high][high] = device_ctx.chan_width.x_list[high]; + for (size_t low = 0; low < high; low++) { + chanx_place_cost_fac[high][low] = chanx_place_cost_fac[high - 1][low] + + device_ctx.chan_width.x_list[high]; + } + } + + /* Now compute the inverse of the average number of tracks per channel * + * between high and low. The cost function divides by the average * + * number of tracks per channel, so by storing the inverse I convert * + * this to a faster multiplication. Take this final number to the * + * place_cost_exp power -- numbers other than one mean this is no * + * longer a simple "average number of tracks"; it is some power of * + * that, allowing greater penalization of narrow channels. */ + + for (size_t high = 0; high < device_ctx.grid.height(); high++) + for (size_t low = 0; low <= high; low++) { + /* Since we will divide the wiring cost by the average channel * + * capacity between high and low, having only 0 width channels * + * will result in infinite wiring capacity normalization * + * factor, and extremely bad placer behaviour. Hence we change * + * this to a small (1 track) channel capacity instead. */ + if (chanx_place_cost_fac[high][low] == 0.0f) { + VTR_LOG_WARN("CHANX place cost fac is 0 at %d %d\n", high, low); + chanx_place_cost_fac[high][low] = 1.0f; + } + + chanx_place_cost_fac[high][low] = (high - low + 1.) + / chanx_place_cost_fac[high][low]; + chanx_place_cost_fac[high][low] = pow( + (double)chanx_place_cost_fac[high][low], + (double)place_cost_exp); + } + + /* Now do the same thing for the y-directed channels. First get the * + * number of tracks between channel high and channel low, inclusive. */ + + chany_place_cost_fac[0][0] = device_ctx.chan_width.y_list[0]; + + for (size_t high = 1; high < device_ctx.grid.width(); high++) { + chany_place_cost_fac[high][high] = device_ctx.chan_width.y_list[high]; + for (size_t low = 0; low < high; low++) { + chany_place_cost_fac[high][low] = chany_place_cost_fac[high - 1][low] + + device_ctx.chan_width.y_list[high]; + } + } + + /* Now compute the inverse of the average number of tracks per channel * + * between high and low. Take to specified power. */ + + for (size_t high = 0; high < device_ctx.grid.width(); high++) + for (size_t low = 0; low <= high; low++) { + /* Since we will divide the wiring cost by the average channel * + * capacity between high and low, having only 0 width channels * + * will result in infinite wiring capacity normalization * + * factor, and extremely bad placer behaviour. Hence we change * + * this to a small (1 track) channel capacity instead. */ + if (chany_place_cost_fac[high][low] == 0.0f) { + VTR_LOG_WARN("CHANY place cost fac is 0 at %d %d\n", high, low); + chany_place_cost_fac[high][low] = 1.0f; + } + + chany_place_cost_fac[high][low] = (high - low + 1.) + / chany_place_cost_fac[high][low]; + chany_place_cost_fac[high][low] = pow( + (double)chany_place_cost_fac[high][low], + (double)place_cost_exp); + } } -static void check_place(const t_placer_costs &costs, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, - const t_place_algorithm &place_algorithm) { - /* Checks that the placement has not confused our data structures. * - * i.e. the clb and block structures agree about the locations of * - * every block, blocks are in legal spots, etc. Also recomputes * - * the final placement cost from scratch and makes sure it is * - * within roundoff of what we think the cost is. */ - - int error = 0; - - error += check_placement_consistency(); - error += check_placement_costs(costs, delay_model, criticalities, - place_algorithm); - error += check_placement_floorplanning(); - - if (error == 0) { - VTR_LOG("\n"); - VTR_LOG("Completed placement consistency check successfully.\n"); - - } else { - VPR_ERROR(VPR_ERROR_PLACE, - "\nCompleted placement consistency check, %d errors found.\n" - "Aborting program.\n", error); - } +static void check_place(const t_placer_costs& costs, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + const t_place_algorithm& place_algorithm) { + /* Checks that the placement has not confused our data structures. * + * i.e. the clb and block structures agree about the locations of * + * every block, blocks are in legal spots, etc. Also recomputes * + * the final placement cost from scratch and makes sure it is * + * within roundoff of what we think the cost is. */ + + int error = 0; + + error += check_placement_consistency(); + error += check_placement_costs(costs, delay_model, criticalities, + place_algorithm); + error += check_placement_floorplanning(); + + if (error == 0) { + VTR_LOG("\n"); + VTR_LOG("Completed placement consistency check successfully.\n"); + + } else { + VPR_ERROR(VPR_ERROR_PLACE, + "\nCompleted placement consistency check, %d errors found.\n" + "Aborting program.\n", + error); + } } -static int check_placement_costs(const t_placer_costs &costs, - const PlaceDelayModel *delay_model, - const PlacerCriticalities *criticalities, - const t_place_algorithm &place_algorithm) { - int error = 0; - double bb_cost_check; - double timing_cost_check; - - bb_cost_check = comp_bb_cost(CHECK); - if (fabs(bb_cost_check - costs.bb_cost) > costs.bb_cost * ERROR_TOL) { - VTR_LOG_ERROR( - "bb_cost_check: %g and bb_cost: %g differ in check_place.\n", - bb_cost_check, costs.bb_cost); - error++; - } - - if (place_algorithm.is_timing_driven()) { - comp_td_costs(delay_model, *criticalities, &timing_cost_check); - //VTR_LOG("timing_cost recomputed from scratch: %g\n", timing_cost_check); - if (fabs( - timing_cost_check - - costs.timing_cost) > costs.timing_cost * ERROR_TOL) { - VTR_LOG_ERROR( - "timing_cost_check: %g and timing_cost: %g differ in check_place.\n", - timing_cost_check, costs.timing_cost); - error++; - } - } - return error; +static int check_placement_costs(const t_placer_costs& costs, + const PlaceDelayModel* delay_model, + const PlacerCriticalities* criticalities, + const t_place_algorithm& place_algorithm) { + int error = 0; + double bb_cost_check; + double timing_cost_check; + + bb_cost_check = comp_bb_cost(CHECK); + if (fabs(bb_cost_check - costs.bb_cost) > costs.bb_cost * ERROR_TOL) { + VTR_LOG_ERROR( + "bb_cost_check: %g and bb_cost: %g differ in check_place.\n", + bb_cost_check, costs.bb_cost); + error++; + } + + if (place_algorithm.is_timing_driven()) { + comp_td_costs(delay_model, *criticalities, &timing_cost_check); + //VTR_LOG("timing_cost recomputed from scratch: %g\n", timing_cost_check); + if (fabs( + timing_cost_check + - costs.timing_cost) + > costs.timing_cost * ERROR_TOL) { + VTR_LOG_ERROR( + "timing_cost_check: %g and timing_cost: %g differ in check_place.\n", + timing_cost_check, costs.timing_cost); + error++; + } + } + return error; } static int check_placement_consistency() { - return check_block_placement_consistency() - + check_macro_placement_consistency(); + return check_block_placement_consistency() + + check_macro_placement_consistency(); } static int check_block_placement_consistency() { @@ -2754,42 +2774,42 @@ static int check_block_placement_consistency() { } int check_macro_placement_consistency() { - int error = 0; - auto &place_ctx = g_vpr_ctx.placement(); - - auto &pl_macros = place_ctx.pl_macros; - - /* Check the pl_macro placement are legal - blocks are in the proper relative position. */ - for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); imacro++) { - auto head_iblk = pl_macros[imacro].members[0].blk_index; - - for (size_t imember = 0; imember < pl_macros[imacro].members.size(); - imember++) { - auto member_iblk = pl_macros[imacro].members[imember].blk_index; - - // Compute the suppossed member's x,y,z location - t_pl_loc member_pos = place_ctx.block_locs[head_iblk].loc - + pl_macros[imacro].members[imember].offset; - - // Check the place_ctx.block_locs data structure first - if (place_ctx.block_locs[member_iblk].loc != member_pos) { - VTR_LOG_ERROR( - "Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", - size_t(member_iblk), imacro); - error++; - } - - // Then check the place_ctx.grid data structure - if (place_ctx.grid_blocks[member_pos.x][member_pos.y].blocks[member_pos.sub_tile] - != member_iblk) { - VTR_LOG_ERROR( - "Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", - size_t(member_iblk), imacro); - error++; - } - } // Finish going through all the members - } // Finish going through all the macros - return error; + int error = 0; + auto& place_ctx = g_vpr_ctx.placement(); + + auto& pl_macros = place_ctx.pl_macros; + + /* Check the pl_macro placement are legal - blocks are in the proper relative position. */ + for (size_t imacro = 0; imacro < place_ctx.pl_macros.size(); imacro++) { + auto head_iblk = pl_macros[imacro].members[0].blk_index; + + for (size_t imember = 0; imember < pl_macros[imacro].members.size(); + imember++) { + auto member_iblk = pl_macros[imacro].members[imember].blk_index; + + // Compute the suppossed member's x,y,z location + t_pl_loc member_pos = place_ctx.block_locs[head_iblk].loc + + pl_macros[imacro].members[imember].offset; + + // Check the place_ctx.block_locs data structure first + if (place_ctx.block_locs[member_iblk].loc != member_pos) { + VTR_LOG_ERROR( + "Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", + size_t(member_iblk), imacro); + error++; + } + + // Then check the place_ctx.grid data structure + if (place_ctx.grid_blocks[member_pos.x][member_pos.y].blocks[member_pos.sub_tile] + != member_iblk) { + VTR_LOG_ERROR( + "Block %zu in pl_macro #%zu is not placed in the proper orientation.\n", + size_t(member_iblk), imacro); + error++; + } + } // Finish going through all the members + } // Finish going through all the macros + return error; } #ifdef VERBOSE @@ -2812,26 +2832,26 @@ static void print_clb_placement(const char* fname) { #endif static void free_try_swap_arrays() { - g_vpr_ctx.mutable_placement().compressed_block_grids.clear(); + g_vpr_ctx.mutable_placement().compressed_block_grids.clear(); } -static void generate_post_place_timing_reports(const t_placer_opts &placer_opts, - const t_analysis_opts &analysis_opts, - const SetupTimingInfo &timing_info, - const PlacementDelayCalculator &delay_calc) { - auto &timing_ctx = g_vpr_ctx.timing(); - auto &atom_ctx = g_vpr_ctx.atom(); +static void generate_post_place_timing_reports(const t_placer_opts& placer_opts, + const t_analysis_opts& analysis_opts, + const SetupTimingInfo& timing_info, + const PlacementDelayCalculator& delay_calc) { + auto& timing_ctx = g_vpr_ctx.timing(); + auto& atom_ctx = g_vpr_ctx.atom(); - VprTimingGraphResolver resolver(atom_ctx.nlist, atom_ctx.lookup, - *timing_ctx.graph, delay_calc); - resolver.set_detail_level(analysis_opts.timing_report_detail); + VprTimingGraphResolver resolver(atom_ctx.nlist, atom_ctx.lookup, + *timing_ctx.graph, delay_calc); + resolver.set_detail_level(analysis_opts.timing_report_detail); - tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, - *timing_ctx.constraints); + tatum::TimingReporter timing_reporter(resolver, *timing_ctx.graph, + *timing_ctx.constraints); - timing_reporter.report_timing_setup( - placer_opts.post_place_timing_report_file, - *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths); + timing_reporter.report_timing_setup( + placer_opts.post_place_timing_report_file, + *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths); } #if 0 @@ -2846,153 +2866,161 @@ static void update_screen_debug() { #endif static void print_place_status_header() { - VTR_LOG( - "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); - VTR_LOG( - "Tnum Time T Av Cost Av BB Cost Av TD Cost CPD sTNS sWNS Ac Rate Std Dev R lim Crit Exp Tot Moves Alpha\n"); - VTR_LOG( - " (sec) (ns) (ns) (ns) \n"); - VTR_LOG( - "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); + VTR_LOG( + "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); + VTR_LOG( + "Tnum Time T Av Cost Av BB Cost Av TD Cost CPD sTNS sWNS Ac Rate Std Dev R lim Crit Exp Tot Moves Alpha\n"); + VTR_LOG( + " (sec) (ns) (ns) (ns) \n"); + VTR_LOG( + "---- ------ ------- ------- ---------- ---------- ------- ---------- -------- ------- ------- ------ -------- --------- ------\n"); } -static void print_place_status(const t_annealing_state &state, - const t_placer_statistics &stats, float elapsed_sec, float cpd, - float sTNS, float sWNS, size_t tot_moves) { - VTR_LOG("%4zu " - "%6.1f " - "%7.1e " - "%7.3f %10.2f %-10.5g " - "%7.3f % 10.3g % 8.3f " - "%7.3f %7.4f %6.1f %8.2f", state.num_temps, elapsed_sec, state.t, - stats.av_cost, stats.av_bb_cost, stats.av_timing_cost, 1e9 * cpd, - 1e9 * sTNS, 1e9 * sWNS, stats.success_rate, stats.std_dev, - state.rlim, state.crit_exponent); - - pretty_print_uint(" ", tot_moves, 9, 3); - - VTR_LOG(" %6.3f\n", state.alpha); - fflush(stdout); +static void print_place_status(const t_annealing_state& state, + const t_placer_statistics& stats, + float elapsed_sec, + float cpd, + float sTNS, + float sWNS, + size_t tot_moves) { + VTR_LOG( + "%4zu " + "%6.1f " + "%7.1e " + "%7.3f %10.2f %-10.5g " + "%7.3f % 10.3g % 8.3f " + "%7.3f %7.4f %6.1f %8.2f", + state.num_temps, elapsed_sec, state.t, + stats.av_cost, stats.av_bb_cost, stats.av_timing_cost, 1e9 * cpd, + 1e9 * sTNS, 1e9 * sWNS, stats.success_rate, stats.std_dev, + state.rlim, state.crit_exponent); + + pretty_print_uint(" ", tot_moves, 9, 3); + + VTR_LOG(" %6.3f\n", state.alpha); + fflush(stdout); } static void print_resources_utilization() { - auto &place_ctx = g_vpr_ctx.placement(); - auto &cluster_ctx = g_vpr_ctx.clustering(); - auto &device_ctx = g_vpr_ctx.device(); - - int max_block_name = 0; - int max_tile_name = 0; - - //Record the resource requirement - std::map num_type_instances; - std::map> num_placed_instances; - for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { - auto block_loc = place_ctx.block_locs[blk_id]; - auto loc = block_loc.loc; - - auto physical_tile = device_ctx.grid[loc.x][loc.y].type; - auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id); - - num_type_instances[logical_block]++; - num_placed_instances[logical_block][physical_tile]++; - - max_block_name = std::max(max_block_name, - strlen(logical_block->name)); - max_tile_name = std::max(max_tile_name, - strlen(physical_tile->name)); - } - - VTR_LOG("\n"); - VTR_LOG("Placement resource usage:\n"); - for (auto logical_block : num_type_instances) { - for (auto physical_tile : num_placed_instances[logical_block.first]) { - VTR_LOG(" %-*s implemented as %-*s: %d\n", max_block_name, - logical_block.first->name, max_tile_name, - physical_tile.first->name, physical_tile.second); - } - } - VTR_LOG("\n"); + auto& place_ctx = g_vpr_ctx.placement(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& device_ctx = g_vpr_ctx.device(); + + int max_block_name = 0; + int max_tile_name = 0; + + //Record the resource requirement + std::map num_type_instances; + std::map> + num_placed_instances; + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + auto block_loc = place_ctx.block_locs[blk_id]; + auto loc = block_loc.loc; + + auto physical_tile = device_ctx.grid[loc.x][loc.y].type; + auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id); + + num_type_instances[logical_block]++; + num_placed_instances[logical_block][physical_tile]++; + + max_block_name = std::max(max_block_name, + strlen(logical_block->name)); + max_tile_name = std::max(max_tile_name, + strlen(physical_tile->name)); + } + + VTR_LOG("\n"); + VTR_LOG("Placement resource usage:\n"); + for (auto logical_block : num_type_instances) { + for (auto physical_tile : num_placed_instances[logical_block.first]) { + VTR_LOG(" %-*s implemented as %-*s: %d\n", max_block_name, + logical_block.first->name, max_tile_name, + physical_tile.first->name, physical_tile.second); + } + } + VTR_LOG("\n"); } -static void print_placement_swaps_stats(const t_annealing_state &state) { - size_t total_swap_attempts = num_swap_rejected + num_swap_accepted - + num_swap_aborted; - VTR_ASSERT(total_swap_attempts > 0); - - size_t num_swap_print_digits = ceil(log10(total_swap_attempts)); - float reject_rate = (float) num_swap_rejected / total_swap_attempts; - float accept_rate = (float) num_swap_accepted / total_swap_attempts; - float abort_rate = (float) num_swap_aborted / total_swap_attempts; - VTR_LOG("Placement number of temperatures: %d\n", state.num_temps); - VTR_LOG("Placement total # of swap attempts: %*d\n", num_swap_print_digits, - total_swap_attempts); - VTR_LOG("\tSwaps accepted: %*d (%4.1f %%)\n", num_swap_print_digits, - num_swap_accepted, 100 * accept_rate); - VTR_LOG("\tSwaps rejected: %*d (%4.1f %%)\n", num_swap_print_digits, - num_swap_rejected, 100 * reject_rate); - VTR_LOG("\tSwaps aborted : %*d (%4.1f %%)\n", num_swap_print_digits, - num_swap_aborted, 100 * abort_rate); +static void print_placement_swaps_stats(const t_annealing_state& state) { + size_t total_swap_attempts = num_swap_rejected + num_swap_accepted + + num_swap_aborted; + VTR_ASSERT(total_swap_attempts > 0); + + size_t num_swap_print_digits = ceil(log10(total_swap_attempts)); + float reject_rate = (float)num_swap_rejected / total_swap_attempts; + float accept_rate = (float)num_swap_accepted / total_swap_attempts; + float abort_rate = (float)num_swap_aborted / total_swap_attempts; + VTR_LOG("Placement number of temperatures: %d\n", state.num_temps); + VTR_LOG("Placement total # of swap attempts: %*d\n", num_swap_print_digits, + total_swap_attempts); + VTR_LOG("\tSwaps accepted: %*d (%4.1f %%)\n", num_swap_print_digits, + num_swap_accepted, 100 * accept_rate); + VTR_LOG("\tSwaps rejected: %*d (%4.1f %%)\n", num_swap_print_digits, + num_swap_rejected, 100 * reject_rate); + VTR_LOG("\tSwaps aborted : %*d (%4.1f %%)\n", num_swap_print_digits, + num_swap_aborted, 100 * abort_rate); } static void print_placement_move_types_stats( - const MoveTypeStat &move_type_stat) { - float moves, accepted, rejected, aborted; - float total_moves = std::accumulate(move_type_stat.num_moves.begin(), - move_type_stat.num_moves.end(), 0.0); - - std::string move_name; - VTR_LOG("\n\nPercentage of different move types:\n"); - - for (size_t i = 0; i < move_type_stat.num_moves.size(); i++) { - moves = move_type_stat.num_moves[i]; - if (moves != 0) { - accepted = move_type_stat.accepted_moves[i]; - aborted = move_type_stat.aborted_moves[i]; - rejected = moves - (accepted + aborted); - move_name = move_type_to_string(e_move_type(i)); - VTR_LOG( - "\t%.17s move: %2.2f %% (acc=%2.2f %%, rej=%2.2f %%, aborted=%2.2f %%)\n", - move_name.c_str(), 100 * moves / total_moves, - 100 * accepted / moves, 100 * rejected / moves, - 100 * aborted / moves); - } - } - VTR_LOG("\n"); + const MoveTypeStat& move_type_stat) { + float moves, accepted, rejected, aborted; + float total_moves = std::accumulate(move_type_stat.num_moves.begin(), + move_type_stat.num_moves.end(), 0.0); + + std::string move_name; + VTR_LOG("\n\nPercentage of different move types:\n"); + + for (size_t i = 0; i < move_type_stat.num_moves.size(); i++) { + moves = move_type_stat.num_moves[i]; + if (moves != 0) { + accepted = move_type_stat.accepted_moves[i]; + aborted = move_type_stat.aborted_moves[i]; + rejected = moves - (accepted + aborted); + move_name = move_type_to_string(e_move_type(i)); + VTR_LOG( + "\t%.17s move: %2.2f %% (acc=%2.2f %%, rej=%2.2f %%, aborted=%2.2f %%)\n", + move_name.c_str(), 100 * moves / total_moves, + 100 * accepted / moves, 100 * rejected / moves, + 100 * aborted / moves); + } + } + VTR_LOG("\n"); } static void calculate_reward_and_process_outcome( - const t_placer_opts &placer_opts, - const MoveOutcomeStats &move_outcome_stats, const double &delta_c, - float timing_bb_factor, MoveGenerator &move_generator) { - std::string reward_fun_string = placer_opts.place_reward_fun; - e_reward_function reward_fun = string_to_reward(reward_fun_string); - - if (reward_fun == BASIC) { - move_generator.process_outcome(-1 * delta_c, reward_fun); - } else if (reward_fun == NON_PENALIZING_BASIC - || reward_fun == RUNTIME_AWARE) { - if (delta_c < 0) { - move_generator.process_outcome(-1 * delta_c, reward_fun); - } else { - move_generator.process_outcome(0, reward_fun); - } - } else if (reward_fun == WL_BIASED_RUNTIME_AWARE) { - if (delta_c < 0) { - float reward = -1 - * (move_outcome_stats.delta_cost_norm - + (0.5 - timing_bb_factor) - * move_outcome_stats.delta_timing_cost_norm - + timing_bb_factor - * move_outcome_stats.delta_bb_cost_norm); - move_generator.process_outcome(reward, reward_fun); - } else { - move_generator.process_outcome(0, reward_fun); - } - } + const t_placer_opts& placer_opts, + const MoveOutcomeStats& move_outcome_stats, + const double& delta_c, + float timing_bb_factor, + MoveGenerator& move_generator) { + std::string reward_fun_string = placer_opts.place_reward_fun; + e_reward_function reward_fun = string_to_reward(reward_fun_string); + + if (reward_fun == BASIC) { + move_generator.process_outcome(-1 * delta_c, reward_fun); + } else if (reward_fun == NON_PENALIZING_BASIC + || reward_fun == RUNTIME_AWARE) { + if (delta_c < 0) { + move_generator.process_outcome(-1 * delta_c, reward_fun); + } else { + move_generator.process_outcome(0, reward_fun); + } + } else if (reward_fun == WL_BIASED_RUNTIME_AWARE) { + if (delta_c < 0) { + float reward = -1 + * (move_outcome_stats.delta_cost_norm + + (0.5 - timing_bb_factor) + * move_outcome_stats.delta_timing_cost_norm + + timing_bb_factor + * move_outcome_stats.delta_bb_cost_norm); + move_generator.process_outcome(reward, reward_fun); + } else { + move_generator.process_outcome(0, reward_fun); + } + } } -bool placer_needs_lookahead(const t_vpr_setup &vpr_setup) { - return (vpr_setup.PlacerOpts.place_algorithm.is_timing_driven()); +bool placer_needs_lookahead(const t_vpr_setup& vpr_setup) { + return (vpr_setup.PlacerOpts.place_algorithm.is_timing_driven()); } - diff --git a/vpr/src/place/placer_breakpoint.cpp b/vpr/src/place/placer_breakpoint.cpp index f4bb1639089..4b23862daf9 100644 --- a/vpr/src/place/placer_breakpoint.cpp +++ b/vpr/src/place/placer_breakpoint.cpp @@ -18,7 +18,6 @@ void transform_blocks_affected(t_pl_blocks_to_be_moved blocksAffected) { } void stop_placement_and_check_breakpoints(t_pl_blocks_to_be_moved& blocks_affected, e_move_result move_outcome, double delta_c, double bb_delta_c, double timing_delta_c) { - t_draw_state* draw_state = get_draw_state_vars(); if (draw_state->list_of_breakpoints.size() != 0) { //update current information From 02f9975d44c0234a5cf57d544e1e842edd57b719 Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 13 Jul 2021 14:07:37 -0400 Subject: [PATCH 14/46] Solved warnings for ManualMoveGenerator class and added code guards to draw_debug.h file (to reduce warning as well) --- vpr/src/draw/draw_debug.h | 7 ++++++- vpr/src/draw/manual_moves.cpp | 2 +- vpr/src/draw/manual_moves.h | 2 +- vpr/src/place/place.cpp | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/vpr/src/draw/draw_debug.h b/vpr/src/draw/draw_debug.h index c50f93162f2..e02b360e726 100644 --- a/vpr/src/draw/draw_debug.h +++ b/vpr/src/draw/draw_debug.h @@ -1,4 +1,7 @@ /** This file contains all functions reagrding the graphics related to the setting of place and route breakpoints **/ +#ifndef DRAW_DEBUG_H +#define DRAW_DEBUG_H + #ifndef NO_GRAPHICS # include "breakpoint.h" @@ -35,4 +38,6 @@ void invalid_breakpoint_entry_window(std::string error); bool valid_expression(std::string exp); void breakpoint_info_window(std::string bpDescription, BreakpointState draw_breakpoint_state, bool in_placer); -#endif +#endif /*NO_GRAPHICS*/ + +#endif /*DRAW_DEBUG_H*/ diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 8f4c229a28c..e426ad803eb 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -170,7 +170,7 @@ ManualMovesGlobals* get_manual_moves_global() { } //Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/) { +e_create_move ManualMoveGenerator::propose_move_mm(t_pl_blocks_to_be_moved& blocks_affected) { int block_id = manual_moves_global.manual_move_info.blockID; t_pl_loc to = manual_moves_global.manual_move_info.to_location; ClusterBlockId b_from = ClusterBlockId(block_id); diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 1d6bf1d17fb..dfd0871310e 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -46,7 +46,7 @@ struct ManualMovesGlobals { class ManualMoveGenerator : public MoveGenerator { public: //Evaluates if move is successful and legal or unable to do. - e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, float /*rlim*/); + e_create_move propose_move_mm(t_pl_blocks_to_be_moved& blocks_affected); }; class Timer { diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 70459ebc837..e918c3217bd 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1327,7 +1327,7 @@ static e_move_result try_swap(const t_annealing_state* state, draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - create_move_outcome = manual_move_generator.propose_move(blocks_affected, rlim); + create_move_outcome = manual_move_generator.propose_move_mm(blocks_affected); } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); From ca0a7663ad246a786ec8226028348a964991b452 Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 13 Jul 2021 15:37:21 -0400 Subject: [PATCH 15/46] Fixed gtk warnings --- vpr/src/draw/manual_moves.cpp | 11 +++++++---- vpr/src/draw/manual_moves.h | 2 +- vpr/src/place/place.h | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index e426ad803eb..d9cf65e3ed6 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -95,8 +95,8 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { } //if the block is not found if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { - invalid_breakpoint_entry_window("Invalid block ID/Name"); valid_input = false; + invalid_breakpoint_entry_window("Invalid block ID/Name"); } GtkWidget* x_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 1); @@ -112,17 +112,19 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { if (!is_legal_swap_to_location(ClusterBlockId(block_id), to)) { valid_input = false; } + //If the block requested is already in that location. ClusterBlockId current_block = ClusterBlockId(block_id); t_pl_loc current_block_loc = place_ctx.block_locs[current_block].loc; if (x_location == current_block_loc.x && y_location == current_block_loc.y && subtile_location == current_block_loc.sub_tile) { - invalid_breakpoint_entry_window("The block is currently in this location"); valid_input = false; + invalid_breakpoint_entry_window("The block is currently in this location"); } + //Checks if all fields from the user input window are complete. if (std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { - invalid_breakpoint_entry_window("Not all fields are complete"); valid_input = false; + invalid_breakpoint_entry_window("Not all fields are complete"); } if (valid_input) { @@ -219,7 +221,8 @@ void cost_summary_dialog() { GTK_RESPONSE_REJECT, NULL); - gtk_widget_set_halign(gtk_dialog_get_action_area((GtkDialog*)dialog), GTK_ALIGN_CENTER); + //Find function so substitute this one because it is deprecated + //gtk_widget_set_halign(gtk_dialog_get_action_area((GtkDialog*)dialog), GTK_ALIGN_CENTER); //Create elements for the dialog and printing costs to the user. GtkWidget* title_label = gtk_label_new(NULL); diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index dfd0871310e..fdb4ca2daea 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -46,7 +46,7 @@ struct ManualMovesGlobals { class ManualMoveGenerator : public MoveGenerator { public: //Evaluates if move is successful and legal or unable to do. - e_create_move propose_move_mm(t_pl_blocks_to_be_moved& blocks_affected); + e_create_move propose_move_mm(t_pl_blocks_to_be_moved& blocks_affected); }; class Timer { diff --git a/vpr/src/place/place.h b/vpr/src/place/place.h index d5f7ce71d27..4bd161ec64d 100644 --- a/vpr/src/place/place.h +++ b/vpr/src/place/place.h @@ -2,7 +2,6 @@ #define VPR_PLACE_H #include "vpr_types.h" -#include "manual_moves.h" void try_place(const t_placer_opts& placer_opts, t_annealing_sched annealing_sched, From 8561ffcc11b3aa64ad32ff781ca0b8e115a88fd6 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 14 Jul 2021 17:23:35 -0400 Subject: [PATCH 16/46] Implemented separate function to check legality. Now included in manual_moves.cpp instead of move_utils --- vpr/src/draw/manual_moves.cpp | 74 ++++++++++++++++++++++++----------- vpr/src/draw/manual_moves.h | 3 +- vpr/src/place/move_utils.cpp | 12 ------ 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index d9cf65e3ed6..20b2dfe08ce 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -82,7 +82,6 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { //Loading the context/data structures needed. auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.placement(); //Getting entry values GtkWidget* block_entry = gtk_grid_get_child_at((GtkGrid*)grid, 0, 1); @@ -93,11 +92,6 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { } else { //for block name block_id = size_t(cluster_ctx.clb_nlist.find_block(gtk_entry_get_text((GtkEntry*)block_entry))); } - //if the block is not found - if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { - valid_input = false; - invalid_breakpoint_entry_window("Invalid block ID/Name"); - } GtkWidget* x_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 1); GtkWidget* y_position_entry = gtk_grid_get_child_at((GtkGrid*)grid, 2, 2); @@ -107,25 +101,13 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { y_location = std::atoi(gtk_entry_get_text((GtkEntry*)y_position_entry)); subtile_location = std::atoi(gtk_entry_get_text((GtkEntry*)subtile_position_entry)); - //Function in move_utils.cpp that returns true if the location swap is valid - t_pl_loc to = t_pl_loc(x_location, y_location, subtile_location); - if (!is_legal_swap_to_location(ClusterBlockId(block_id), to)) { - valid_input = false; - } - - //If the block requested is already in that location. - ClusterBlockId current_block = ClusterBlockId(block_id); - t_pl_loc current_block_loc = place_ctx.block_locs[current_block].loc; - if (x_location == current_block_loc.x && y_location == current_block_loc.y && subtile_location == current_block_loc.sub_tile) { - valid_input = false; - invalid_breakpoint_entry_window("The block is currently in this location"); + if(std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { + invalid_breakpoint_entry_window("Not all fields are complete"); + valid_input = false; } - //Checks if all fields from the user input window are complete. - if (std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { - valid_input = false; - invalid_breakpoint_entry_window("Not all fields are complete"); - } + t_pl_loc to = t_pl_loc(x_location, y_location, subtile_location); + valid_input = checking_legality_conditions(ClusterBlockId(block_id), to); if (valid_input) { manual_moves_global.manual_move_info.valid_input = true; @@ -150,6 +132,52 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { } } +bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { + + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + auto& device_ctx = g_vpr_ctx.device(); + + //if the block is not found + if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { + invalid_breakpoint_entry_window("Invalid block ID/Name"); + return false; + } + + //If the dimensions are out of bounds + if (to.x < 0 || to.x >= int(device_ctx.grid.width()) + || to.y < 0 || to.y >= int(device_ctx.grid.height())) { + invalid_breakpoint_entry_window("Dimensions are out of bounds"); + return false; + } + + //If the block s not compatible + auto physical_tile = device_ctx.grid[to.x][to.y].type; + auto logical_block = cluster_ctx.clb_nlist.block_type(block_id); + if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { + invalid_breakpoint_entry_window("Blocks are not compatible"); + return false; + } + + //If the destination block is user constrained, abort this swap + auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; + if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { + if (place_ctx.block_locs[b_to].is_fixed) { + invalid_breakpoint_entry_window("Block is fixed"); + return false; + } + } + + //If the block requested is already in that location. + t_pl_loc current_block_loc = place_ctx.block_locs[block_id].loc; + if (to.x == current_block_loc.x && to.y == current_block_loc.y && to.sub_tile == current_block_loc.sub_tile) { + invalid_breakpoint_entry_window("The block is currently in this location"); + return false; + } + + return true; +} + bool string_is_a_number(std::string block_id) { for (size_t i = 0; i < block_id.size(); i++) { //Returns 0 if the string does not have characters from 0-9 diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index fdb4ca2daea..0ba5c290716 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -78,8 +78,9 @@ class Timer { void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); +//bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to); +bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to); bool string_is_a_number(std::string block_id); -//bool get_manual_move_flag(); void get_manual_move_flag(); void cost_summary_dialog(); ManualMovesGlobals* get_manual_moves_global(); diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index ecbdc38dd1f..929a6780943 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -451,14 +451,8 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.placement(); - //For manual moves feature - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - if (to.x < 0 || to.x >= int(device_ctx.grid.width()) || to.y < 0 || to.y >= int(device_ctx.grid.height())) { - if (manual_move_global->manual_move_flag) { - invalid_breakpoint_entry_window("Dimensions are out of bounds"); - } return false; } @@ -467,18 +461,12 @@ bool is_legal_swap_to_location(ClusterBlockId blk, t_pl_loc to) { if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { - if (manual_move_global->manual_move_flag) { - invalid_breakpoint_entry_window("Blocks are not compatible"); - } return false; } // If the destination block is user constrained, abort this swap auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { if (place_ctx.block_locs[b_to].is_fixed) { - if (manual_move_global->manual_move_flag) { - invalid_breakpoint_entry_window("Block is fixed"); - } return false; } } From 59fa37d6389efc6a4644561550546caaabc82f8c Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 14 Jul 2021 20:14:55 -0400 Subject: [PATCH 17/46] Added NO_GRAPHICS guards in place.cpp for manual moves --- vpr/src/place/place.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index e918c3217bd..5b1c2eb301f 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1319,14 +1319,17 @@ static e_move_result try_swap(const t_annealing_state* state, rlim = state->rlim; } +#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - - e_create_move create_move_outcome; - if (manual_move_global->manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + } +#endif /*NO_GRAPHICS*/ + + e_create_move create_move_outcome; + if(manual_move_global->manual_move_flag) { create_move_outcome = manual_move_generator.propose_move_mm(blocks_affected); } else { //Generate a new move (perturbation) used to explore the space of possible placements @@ -1417,6 +1420,7 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); +#ifndef NO_GRAPHICS if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); @@ -1424,6 +1428,7 @@ static e_move_result try_swap(const t_annealing_state* state, //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } +#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; @@ -1461,7 +1466,9 @@ static e_move_result try_swap(const t_annealing_state* state, ++move_type_stat.accepted_moves[(int)move_type]; //Highlights the new block when manual move is selected. +#ifndef NO_GRAPHICS highlight_new_block_location(manual_move_global->manual_move_flag); +#endif /*NO_GRPAHICS*/ } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); From f90bee8577f648c41a55715616c213366e9c4af0 Mon Sep 17 00:00:00 2001 From: Paula Date: Thu, 15 Jul 2021 12:38:22 -0400 Subject: [PATCH 18/46] Moved manual move generator to a new file and added NO_GRAPHICS on draw.cpp --- vpr/src/draw/draw.cpp | 2 + vpr/src/draw/manual_moves.cpp | 126 +++++++++--------------- vpr/src/draw/manual_moves.h | 15 ++- vpr/src/place/manual_move_generator.cpp | 41 ++++++++ vpr/src/place/manual_move_generator.h | 22 +++++ vpr/src/place/place.cpp | 13 +-- 6 files changed, 123 insertions(+), 96 deletions(-) create mode 100644 vpr/src/place/manual_move_generator.cpp create mode 100644 vpr/src/place/manual_move_generator.h diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 5adc801b60c..1ee870f6af0 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -4369,6 +4369,7 @@ static void highlight_blocks(double x, double y) { place_ctx.block_locs[clb_index].loc.y); } +# ifndef NO_GRAPHICS //If manual moves is activated, then user can select block from the grid. ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { @@ -4377,6 +4378,7 @@ static void highlight_blocks(double x, double y) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } +# endif /*NO_GRAPHICS*/ application.update_message(msg); application.refresh_drawing(); diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 20b2dfe08ce..59d0a8b261a 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -101,9 +101,9 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { y_location = std::atoi(gtk_entry_get_text((GtkEntry*)y_position_entry)); subtile_location = std::atoi(gtk_entry_get_text((GtkEntry*)subtile_position_entry)); - if(std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { - invalid_breakpoint_entry_window("Not all fields are complete"); - valid_input = false; + if (std::string(gtk_entry_get_text((GtkEntry*)block_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)x_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)y_position_entry)).empty() || std::string(gtk_entry_get_text((GtkEntry*)subtile_position_entry)).empty()) { + invalid_breakpoint_entry_window("Not all fields are complete"); + valid_input = false; } t_pl_loc to = t_pl_loc(x_location, y_location, subtile_location); @@ -133,49 +133,48 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { } bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + auto& device_ctx = g_vpr_ctx.device(); + + //if the block is not found + if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { + invalid_breakpoint_entry_window("Invalid block ID/Name"); + return false; + } + + //If the dimensions are out of bounds + if (to.x < 0 || to.x >= int(device_ctx.grid.width()) + || to.y < 0 || to.y >= int(device_ctx.grid.height())) { + invalid_breakpoint_entry_window("Dimensions are out of bounds"); + return false; + } - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& place_ctx = g_vpr_ctx.placement(); - auto& device_ctx = g_vpr_ctx.device(); - - //if the block is not found - if ((!cluster_ctx.clb_nlist.valid_block_id(ClusterBlockId(block_id)))) { - invalid_breakpoint_entry_window("Invalid block ID/Name"); - return false; - } - - //If the dimensions are out of bounds - if (to.x < 0 || to.x >= int(device_ctx.grid.width()) - || to.y < 0 || to.y >= int(device_ctx.grid.height())) { - invalid_breakpoint_entry_window("Dimensions are out of bounds"); - return false; - } - - //If the block s not compatible - auto physical_tile = device_ctx.grid[to.x][to.y].type; - auto logical_block = cluster_ctx.clb_nlist.block_type(block_id); - if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { - invalid_breakpoint_entry_window("Blocks are not compatible"); - return false; - } - - //If the destination block is user constrained, abort this swap - auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; - if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { - if (place_ctx.block_locs[b_to].is_fixed) { - invalid_breakpoint_entry_window("Block is fixed"); - return false; - } - } - - //If the block requested is already in that location. - t_pl_loc current_block_loc = place_ctx.block_locs[block_id].loc; - if (to.x == current_block_loc.x && to.y == current_block_loc.y && to.sub_tile == current_block_loc.sub_tile) { - invalid_breakpoint_entry_window("The block is currently in this location"); - return false; - } - - return true; + //If the block s not compatible + auto physical_tile = device_ctx.grid[to.x][to.y].type; + auto logical_block = cluster_ctx.clb_nlist.block_type(block_id); + if (to.sub_tile < 0 || to.sub_tile >= physical_tile->capacity || !is_sub_tile_compatible(physical_tile, logical_block, to.sub_tile)) { + invalid_breakpoint_entry_window("Blocks are not compatible"); + return false; + } + + //If the destination block is user constrained, abort this swap + auto b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; + if (b_to != INVALID_BLOCK_ID && b_to != EMPTY_BLOCK_ID) { + if (place_ctx.block_locs[b_to].is_fixed) { + invalid_breakpoint_entry_window("Block is fixed"); + return false; + } + } + + //If the block requested is already in that location. + t_pl_loc current_block_loc = place_ctx.block_locs[block_id].loc; + if (to.x == current_block_loc.x && to.y == current_block_loc.y && to.sub_tile == current_block_loc.sub_tile) { + invalid_breakpoint_entry_window("The block is currently in this location"); + return false; + } + + return true; } bool string_is_a_number(std::string block_id) { @@ -192,49 +191,12 @@ void get_manual_move_flag() { GObject* manual_moves = application.get_object("manualMove"); //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); - //return manual_moves_global.manual_move_flag; } ManualMovesGlobals* get_manual_moves_global() { return &manual_moves_global; } -//Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move_mm(t_pl_blocks_to_be_moved& blocks_affected) { - int block_id = manual_moves_global.manual_move_info.blockID; - t_pl_loc to = manual_moves_global.manual_move_info.to_location; - ClusterBlockId b_from = ClusterBlockId(block_id); - - //Checking if the block was found - if (!b_from) { - return e_create_move::ABORT; //No movable block was found - } - - auto& place_ctx = g_vpr_ctx.placement(); - auto& cluster_ctx = g_vpr_ctx.clustering(); - auto& device_ctx = g_vpr_ctx.device(); - - //Gets the current location of the block to move. - t_pl_loc from = place_ctx.block_locs[b_from].loc; - auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); - auto grid_from_type = device_ctx.grid[from.x][from.y].type; - VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); - - //Retrieving the compressed block grid for this block type - const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; - //Checking if the block has a compatible subtile. - auto to_type = device_ctx.grid[to.x][to.y].type; - auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); - - //No compatible subtile is found. - if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { - return e_create_move::ABORT; - } - - e_create_move create_move = ::create_move(blocks_affected, b_from, to); - return create_move; -} - void cost_summary_dialog() { GtkWidget* dialog; GtkWidget* content_area; diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 0ba5c290716..cbd780e8d2c 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -10,6 +10,13 @@ # include "move_generator.h" # include "ezgl/application.hpp" # include "ezgl/graphics.hpp" +# include "median_move_generator.h" +# include "weighted_median_move_generator.h" +# include "weighted_centroid_move_generator.h" +# include "feasible_region_move_generator.h" +# include "uniform_move_generator.h" +# include "critical_uniform_move_generator.h" +# include "centroid_move_generator.h" # include # include @@ -42,13 +49,6 @@ struct ManualMovesGlobals { bool manual_move_flag = false; }; -/** Manual Moves Generator, inherits from MoveGenerator class **/ -class ManualMoveGenerator : public MoveGenerator { - public: - //Evaluates if move is successful and legal or unable to do. - e_create_move propose_move_mm(t_pl_blocks_to_be_moved& blocks_affected); -}; - class Timer { public: Timer() { @@ -78,7 +78,6 @@ class Timer { void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); -//bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to); bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to); bool string_is_a_number(std::string block_id); void get_manual_move_flag(); diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp new file mode 100644 index 00000000000..d0cbd63b0f8 --- /dev/null +++ b/vpr/src/place/manual_move_generator.cpp @@ -0,0 +1,41 @@ +#include "manual_move_generator.h" +#include "manual_moves.h" + +//Manual Move Generator function +e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected) { + //e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { + + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + int block_id = manual_move_global->manual_move_info.blockID; + t_pl_loc to = manual_move_global->manual_move_info.to_location; + ClusterBlockId b_from = ClusterBlockId(block_id); + + //Checking if the block was found + if (!b_from) { + return e_create_move::ABORT; //No movable block was found + } + + auto& place_ctx = g_vpr_ctx.placement(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& device_ctx = g_vpr_ctx.device(); + + //Gets the current location of the block to move. + t_pl_loc from = place_ctx.block_locs[b_from].loc; + auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); + auto grid_from_type = device_ctx.grid[from.x][from.y].type; + VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); + + //Retrieving the compressed block grid for this block type + const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; + //Checking if the block has a compatible subtile. + auto to_type = device_ctx.grid[to.x][to.y].type; + auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); + + //No compatible subtile is found. + if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { + return e_create_move::ABORT; + } + + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + return create_move; +} diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h new file mode 100644 index 00000000000..b43976ab3b7 --- /dev/null +++ b/vpr/src/place/manual_move_generator.h @@ -0,0 +1,22 @@ +#ifndef VPR_MANUAL_MOVE_GEN_H +#define VPR_MANUAL_MOVE_GEN_H + +#include "move_generator.h" +#include "median_move_generator.h" +#include "weighted_median_move_generator.h" +#include "weighted_centroid_move_generator.h" +#include "feasible_region_move_generator.h" +#include "uniform_move_generator.h" +#include "critical_uniform_move_generator.h" +#include "centroid_move_generator.h" +#include + +/** Manual Moves Generator, inherits from MoveGenerator class **/ +class ManualMoveGenerator : public MoveGenerator { + public: + //Evaluates if move is successful and legal or unable to do. + e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected); + //e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/); +}; + +#endif \ No newline at end of file diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 5b1c2eb301f..4e3374551dd 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -45,6 +45,7 @@ #include "static_move_generator.h" #include "simpleRL_move_generator.h" +#include "manual_move_generator.h" #include "PlacementDelayCalculator.h" #include "VprTimingGraphResolver.h" @@ -1179,8 +1180,10 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t (int)cluster_ctx.clb_nlist.blocks().size()); for (int i = 0; i < move_lim; i++) { +#ifndef NO_GRAPHICS //Checks manual move flag for manual move feature get_manual_move_flag(); +#endif /*NO_GRAPHICS*/ //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack e_move_result swap_result = try_swap(state, costs, move_generator, @@ -1319,22 +1322,20 @@ static e_move_result try_swap(const t_annealing_state* state, rlim = state->rlim; } + e_create_move create_move_outcome; + #ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - } -#endif /*NO_GRAPHICS*/ - - e_create_move create_move_outcome; - if(manual_move_global->manual_move_flag) { - create_move_outcome = manual_move_generator.propose_move_mm(blocks_affected); + create_move_outcome = manual_move_generator.propose_move(blocks_affected); } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } +#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); From 37eacf676eb7ec652d05fc3f5e376e7fd8e4ca44 Mon Sep 17 00:00:00 2001 From: Paula Date: Thu, 15 Jul 2021 14:44:13 -0400 Subject: [PATCH 19/46] Added no graphics guards to manual move generator files. --- vpr/src/draw/draw.cpp | 2 -- vpr/src/place/manual_move_generator.cpp | 6 ++++-- vpr/src/place/manual_move_generator.h | 26 ++++++++++++++----------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 1ee870f6af0..5adc801b60c 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -4369,7 +4369,6 @@ static void highlight_blocks(double x, double y) { place_ctx.block_locs[clb_index].loc.y); } -# ifndef NO_GRAPHICS //If manual moves is activated, then user can select block from the grid. ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { @@ -4378,7 +4377,6 @@ static void highlight_blocks(double x, double y) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } -# endif /*NO_GRAPHICS*/ application.update_message(msg); application.refresh_drawing(); diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index d0cbd63b0f8..dfca1c6a322 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -1,10 +1,10 @@ #include "manual_move_generator.h" #include "manual_moves.h" +#ifndef NO_GRAPHICS + //Manual Move Generator function e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected) { - //e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); int block_id = manual_move_global->manual_move_info.blockID; t_pl_loc to = manual_move_global->manual_move_info.to_location; @@ -39,3 +39,5 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; } + +#endif diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index b43976ab3b7..fdfce4c1181 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -1,22 +1,26 @@ #ifndef VPR_MANUAL_MOVE_GEN_H #define VPR_MANUAL_MOVE_GEN_H -#include "move_generator.h" -#include "median_move_generator.h" -#include "weighted_median_move_generator.h" -#include "weighted_centroid_move_generator.h" -#include "feasible_region_move_generator.h" -#include "uniform_move_generator.h" -#include "critical_uniform_move_generator.h" -#include "centroid_move_generator.h" -#include +#ifndef NO_GRAPHICS + +# include "move_generator.h" +# include "median_move_generator.h" +# include "weighted_median_move_generator.h" +# include "weighted_centroid_move_generator.h" +# include "feasible_region_move_generator.h" +# include "uniform_move_generator.h" +# include "critical_uniform_move_generator.h" +# include "centroid_move_generator.h" +# include /** Manual Moves Generator, inherits from MoveGenerator class **/ class ManualMoveGenerator : public MoveGenerator { public: //Evaluates if move is successful and legal or unable to do. + using MoveGenerator::propose_move; e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected); - //e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/); }; -#endif \ No newline at end of file +#endif /*NO_GRAPHICS*/ + +#endif /*VPR_MANUAL_MOVE_GEN_H */ From 6f42dfa0f4c166e03ea94539b284b68ee1d1ed43 Mon Sep 17 00:00:00 2001 From: Paula Date: Thu, 15 Jul 2021 15:20:15 -0400 Subject: [PATCH 20/46] Changed guards in place.cpp --- vpr/src/place/place.cpp | 245 ++++++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 120 deletions(-) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 4e3374551dd..07d0562bafe 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -62,13 +62,16 @@ * compared to the timing cost in the agent's reward function. The reward is calculated as * * -1*(1.5-REWARD_BB_TIMING_RELATIVE_WEIGHT)*timing_cost + (1+REWARD_BB_TIMING_RELATIVE_WEIGHT)*bb_cost) */ -#define REWARD_BB_TIMING_RELATIVE_WEIGHT 0.4 -#ifdef VTR_ENABLE_DEBUG_LOGGING -# include "draw_types.h" -# include "draw_global.h" -# include "draw_color.h" -#endif +#ifndef NO_GRAPHICS + +# define REWARD_BB_TIMING_RELATIVE_WEIGHT 0.4 + +# ifdef VTR_ENABLE_DEBUG_LOGGING +# include "draw_types.h" +# include "draw_global.h" +# include "draw_color.h" +# endif using std::max; using std::min; @@ -77,18 +80,18 @@ using std::min; /* This defines the error tolerance for floating points variables used in * * cost computation. 0.01 means that there is a 1% error tolerance. */ -#define ERROR_TOL .01 +# define ERROR_TOL .01 /* This defines the maximum number of swap attempts before invoking the * * once-in-a-while placement legality check as well as floating point * * variables round-offs check. */ -#define MAX_MOVES_BEFORE_RECOMPUTE 500000 +# define MAX_MOVES_BEFORE_RECOMPUTE 500000 /* Flags for the states of the bounding box. * * Stored as char for memory efficiency. */ -#define NOT_UPDATED_YET 'N' -#define UPDATED_ONCE 'U' -#define GOT_FROM_SCRATCH 'S' +# define NOT_UPDATED_YET 'N' +# define UPDATED_ONCE 'U' +# define GOT_FROM_SCRATCH 'S' /* For comp_cost. NORMAL means use the method that generates updateable * * bounding boxes for speed. CHECK means compute all bounding boxes from * @@ -163,82 +166,82 @@ static const float cross_count[50] = {/* [0..49] */ 1.0, 1.0, 1.0, 1.0828, std::unique_ptr f_move_stats_file(nullptr, vtr::fclose); -#ifdef VTR_ENABLE_DEBUG_LOGGIING -# define LOG_MOVE_STATS_HEADER() \ - do { \ - if (f_move_stats_file) { \ - fprintf(f_move_stats_file.get(), \ - "temp,from_blk,to_blk,from_type,to_type," \ - "blk_count," \ - "delta_cost,delta_bb_cost,delta_td_cost," \ - "outcome,reason\n"); \ - } \ - } while (false) - -# define LOG_MOVE_STATS_PROPOSED(t, affected_blocks) \ - do { \ - if (f_move_stats_file) { \ - auto& place_ctx = g_vpr_ctx.placement(); \ - auto& cluster_ctx = g_vpr_ctx.clustering(); \ - ClusterBlockId b_from = affected_blocks.moved_blocks[0].block_num; \ - \ - t_pl_loc to = affected_blocks.moved_blocks[0].new_loc; \ - ClusterBlockId b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; \ - \ - t_logical_block_type_ptr from_type = cluster_ctx.clb_nlist.block_type(b_from); \ - t_logical_block_type_ptr to_type = nullptr; \ - if (b_to) { \ - to_type = cluster_ctx.clb_nlist.block_type(b_to); \ - } \ - \ - fprintf(f_move_stats_file.get(), \ - "%g," \ - "%d,%d," \ - "%s,%s," \ - "%d,", \ - t, \ - int(size_t(b_from)), int(size_t(b_to)), \ - from_type->name, (to_type ? to_type->name : "EMPTY"), \ - affected_blocks.num_moved_blocks); \ - } \ - } while (false) - -# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ - outcome, reason) \ - do { \ - if (f_move_stats_file) { \ - fprintf(f_move_stats_file.get(), \ - "%g,%g,%g," \ - "%s,%s\n", \ - delta_cost, delta_bb_cost, delta_td_cost, \ - outcome, reason); \ - } \ - } while (false) - -#else - -# define LOG_MOVE_STATS_HEADER() \ - do { \ - fprintf(f_move_stats_file.get(), \ - "VTR_ENABLE_DEBUG_LOGGING disabled " \ - "-- No move stats recorded\n"); \ - } while (false) - -# define LOG_MOVE_STATS_PROPOSED(t, blocks_affected) \ - do { \ - } while (false) - -# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ - outcome, reason) \ - do { \ - } while (false) - -#endif +# ifdef VTR_ENABLE_DEBUG_LOGGIING +# define LOG_MOVE_STATS_HEADER() \ + do { \ + if (f_move_stats_file) { \ + fprintf(f_move_stats_file.get(), \ + "temp,from_blk,to_blk,from_type,to_type," \ + "blk_count," \ + "delta_cost,delta_bb_cost,delta_td_cost," \ + "outcome,reason\n"); \ + } \ + } while (false) + +# define LOG_MOVE_STATS_PROPOSED(t, affected_blocks) \ + do { \ + if (f_move_stats_file) { \ + auto& place_ctx = g_vpr_ctx.placement(); \ + auto& cluster_ctx = g_vpr_ctx.clustering(); \ + ClusterBlockId b_from = affected_blocks.moved_blocks[0].block_num; \ + \ + t_pl_loc to = affected_blocks.moved_blocks[0].new_loc; \ + ClusterBlockId b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; \ + \ + t_logical_block_type_ptr from_type = cluster_ctx.clb_nlist.block_type(b_from); \ + t_logical_block_type_ptr to_type = nullptr; \ + if (b_to) { \ + to_type = cluster_ctx.clb_nlist.block_type(b_to); \ + } \ + \ + fprintf(f_move_stats_file.get(), \ + "%g," \ + "%d,%d," \ + "%s,%s," \ + "%d,", \ + t, \ + int(size_t(b_from)), int(size_t(b_to)), \ + from_type->name, (to_type ? to_type->name : "EMPTY"), \ + affected_blocks.num_moved_blocks); \ + } \ + } while (false) + +# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ + outcome, reason) \ + do { \ + if (f_move_stats_file) { \ + fprintf(f_move_stats_file.get(), \ + "%g,%g,%g," \ + "%s,%s\n", \ + delta_cost, delta_bb_cost, delta_td_cost, \ + outcome, reason); \ + } \ + } while (false) + +# else + +# define LOG_MOVE_STATS_HEADER() \ + do { \ + fprintf(f_move_stats_file.get(), \ + "VTR_ENABLE_DEBUG_LOGGING disabled " \ + "-- No move stats recorded\n"); \ + } while (false) + +# define LOG_MOVE_STATS_PROPOSED(t, blocks_affected) \ + do { \ + } while (false) + +# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ + outcome, reason) \ + do { \ + } while (false) + +# endif /********************* Static subroutines local to place.c *******************/ -#ifdef VERBOSE +# ifdef VERBOSE static void print_clb_placement(const char* fname); -#endif +# endif static void alloc_and_load_placement_structs(float place_cost_exp, const t_placer_opts& placer_opts, @@ -503,7 +506,7 @@ void try_place(const t_placer_opts& placer_opts, initial_placement(placer_opts.pad_loc_type, placer_opts.constraints_file.c_str()); -#ifdef ENABLE_ANALYTIC_PLACE +# ifdef ENABLE_ANALYTIC_PLACE /* * Analytic Placer: * Passes in the initial_placement via vpr_context, and passes its placement back via locations marked on @@ -513,7 +516,7 @@ void try_place(const t_placer_opts& placer_opts, if (placer_opts.enable_analytic_placer) { AnalyticPlacer{}.ap_place(); } -#endif /* ENABLE_ANALYTIC_PLACE */ +# endif /* ENABLE_ANALYTIC_PLACE */ // Update physical pin values for (auto block_id : cluster_ctx.clb_nlist.blocks()) { @@ -728,12 +731,12 @@ void try_place(const t_placer_opts& placer_opts, bool skip_anneal = false; -#ifdef ENABLE_ANALYTIC_PLACE +# ifdef ENABLE_ANALYTIC_PLACE // Analytic placer: When enabled, skip most of the annealing and go straight to quench // TODO: refactor goto label. if (placer_opts.enable_analytic_placer) skip_anneal = true; -#endif /* ENABLE_ANALYTIC_PLACE */ +# endif /* ENABLE_ANALYTIC_PLACE */ //RL agent state definition e_agent_state agent_state = EARLY_IN_THE_ANNEAL; @@ -809,11 +812,11 @@ void try_place(const t_placer_opts& placer_opts, update_screen(ScreenUpdatePriority::MINOR, msg, PLACEMENT, timing_info); -#ifdef VERBOSE +# ifdef VERBOSE if (getEchoEnabled()) { print_clb_placement("first_iteration_clb_placement.echo"); } -#endif +# endif } while (state.outer_loop_update(stats.success_rate, costs, placer_opts, annealing_sched)); /* Outer loop of the simmulated annealing ends */ @@ -896,11 +899,11 @@ void try_place(const t_placer_opts& placer_opts, // TODO: // 1. add some subroutine hierarchy! Too big! -#ifdef VERBOSE +# ifdef VERBOSE if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_END_CLB_PLACEMENT)) { print_clb_placement(getEchoFileName(E_ECHO_END_CLB_PLACEMENT)); } -#endif +# endif check_place(costs, place_delay_model.get(), placer_criticalities.get(), placer_opts.place_algorithm); @@ -986,9 +989,9 @@ static void outer_loop_update_timing_info(const t_placer_opts& placer_opts, /*for normalizing the tradeoff between timing and wirelength (bb) */ if (*outer_crit_iter_count >= placer_opts.recompute_crit_iter || placer_opts.inner_loop_recompute_divider != 0) { -#ifdef VERBOSE +# ifdef VERBOSE VTR_LOG("Outer loop recompute criticalities\n"); -#endif +# endif num_connections = std::max(num_connections, 1); //Avoid division by zero VTR_ASSERT(num_connections > 0); @@ -1059,9 +1062,9 @@ static void placement_inner_loop(const t_annealing_state* state, && inner_iter != state->move_lim - 1) { /*on last iteration don't recompute */ inner_crit_iter_count = 0; -#ifdef VERBOSE +# ifdef VERBOSE VTR_LOG("Inner loop recompute criticalities\n"); -#endif +# endif PlaceCritParams crit_params; crit_params.crit_exponent = state->crit_exponent; @@ -1074,13 +1077,13 @@ static void placement_inner_loop(const t_annealing_state* state, } inner_crit_iter_count++; } -#ifdef VERBOSE +# ifdef VERBOSE VTR_LOG("t = %g cost = %g bb_cost = %g timing_cost = %g move = %d\n", t, costs->cost, costs->bb_cost, costs->timing_cost, inner_iter); if (fabs((costs->bb_cost) - comp_bb_cost(CHECK)) > (costs->bb_cost) * ERROR_TOL) VPR_ERROR(VPR_ERROR_PLACE, "fabs((*bb_cost) - comp_bb_cost(CHECK)) > (*bb_cost) * ERROR_TOL"); -#endif +# endif /* Lines below prevent too much round-off error from accumulating * in the cost over many iterations (due to incremental updates). @@ -1180,10 +1183,10 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t (int)cluster_ctx.clb_nlist.blocks().size()); for (int i = 0; i < move_lim; i++) { -#ifndef NO_GRAPHICS + //#ifndef NO_GRAPHICS //Checks manual move flag for manual move feature get_manual_move_flag(); -#endif /*NO_GRAPHICS*/ + //#endif /*NO_GRAPHICS*/ //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack e_move_result swap_result = try_swap(state, costs, move_generator, @@ -1216,10 +1219,10 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t num_accepted, move_lim); } -#ifdef VERBOSE +# ifdef VERBOSE /* Print stats related to finding the initital temp. */ VTR_LOG("std_dev: %g, average cost: %g, starting temp: %g\n", std_dev, av, 20. * std_dev); -#endif +# endif /* Set the initial temperature to 20 times the standard of deviation */ /* so that the initial temperature adjusts according to the circuit */ @@ -1324,7 +1327,7 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; -#ifndef NO_GRAPHICS + //#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { draw_manual_moves_window(""); @@ -1335,7 +1338,7 @@ static e_move_result try_swap(const t_annealing_state* state, //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } -#endif /*NO_GRAPHICS*/ + //#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1421,7 +1424,7 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); -#ifndef NO_GRAPHICS + //#ifndef NO_GRAPHICS if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); @@ -1429,7 +1432,7 @@ static e_move_result try_swap(const t_annealing_state* state, //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } -#endif /*NO_GRAPHICS*/ + //#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; @@ -1467,9 +1470,9 @@ static e_move_result try_swap(const t_annealing_state* state, ++move_type_stat.accepted_moves[(int)move_type]; //Highlights the new block when manual move is selected. -#ifndef NO_GRAPHICS + //#ifndef NO_GRAPHICS highlight_new_block_location(manual_move_global->manual_move_flag); -#endif /*NO_GRPAHICS*/ + //#endif /*NO_GRPAHICS*/ } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); @@ -1525,20 +1528,20 @@ static e_move_result try_swap(const t_annealing_state* state, calculate_reward_and_process_outcome(placer_opts, move_outcome_stats, delta_c, timing_bb_factor, move_generator); -#ifdef VTR_ENABLE_DEBUG_LOGGING -# ifndef NO_GRAPHICS +# ifdef VTR_ENABLE_DEBUG_LOGGING +# ifndef NO_GRAPHICS stop_placement_and_check_breakpoints(blocks_affected, move_outcome, delta_c, bb_delta_c, timing_delta_c); +# endif # endif -#endif /* Clear the data structure containing block move info */ clear_move_blocks(blocks_affected); //VTR_ASSERT(check_macro_placement_consistency() == 0); -#if 0 +# if 0 //Check that each accepted swap yields a valid placement check_place(*costs, delay_model, place_algorithm); -#endif +# endif return move_outcome; } @@ -1896,9 +1899,9 @@ static void commit_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { //Reverts modifications to proposed_connection_delay and proposed_connection_timing_cost based on //the move proposed in blocks_affected static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { -#ifndef VTR_ASSERT_SAFE_ENABLED +# ifndef VTR_ASSERT_SAFE_ENABLED static_cast(blocks_affected); -#else +# else //Invalidate temp delay & timing cost values to match sanity checks in //comp_td_connection_cost() auto& cluster_ctx = g_vpr_ctx.clustering(); @@ -1914,7 +1917,7 @@ static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { proposed_connection_delay[net][ipin] = INVALID_DELAY; proposed_connection_timing_cost[net][ipin] = INVALID_DELAY; } -#endif +# endif } /** @@ -2820,7 +2823,7 @@ int check_macro_placement_consistency() { return error; } -#ifdef VERBOSE +# ifdef VERBOSE static void print_clb_placement(const char* fname) { /* Prints out the clb placements to a file. */ FILE* fp; @@ -2837,7 +2840,7 @@ static void print_clb_placement(const char* fname) { fclose(fp); } -#endif +# endif static void free_try_swap_arrays() { g_vpr_ctx.mutable_placement().compressed_block_grids.clear(); @@ -2862,7 +2865,7 @@ static void generate_post_place_timing_reports(const t_placer_opts& placer_opts, *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths); } -#if 0 +# if 0 static void update_screen_debug(); //Performs a major (i.e. interactive) placement screen update. @@ -2871,7 +2874,7 @@ static void update_screen_debug(); static void update_screen_debug() { update_screen(ScreenUpdatePriority::MAJOR, "DEBUG", PLACEMENT, nullptr); } -#endif +# endif static void print_place_status_header() { VTR_LOG( @@ -3032,3 +3035,5 @@ static void calculate_reward_and_process_outcome( bool placer_needs_lookahead(const t_vpr_setup& vpr_setup) { return (vpr_setup.PlacerOpts.place_algorithm.is_timing_driven()); } + +#endif /*NO_GRAPHICS*/ From 1ab758b262da97e66261d91d1bc904a85f68124a Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 13:01:00 -0400 Subject: [PATCH 21/46] Added manual move generator code to RL_agent_util.cpp --- vpr/src/place/RL_agent_util.cpp | 9 +- vpr/src/place/RL_agent_util.h | 3 +- vpr/src/place/manual_move_generator.cpp | 26 ++- vpr/src/place/manual_move_generator.h | 12 +- vpr/src/place/place.cpp | 244 ++++++++++++------------ 5 files changed, 165 insertions(+), 129 deletions(-) diff --git a/vpr/src/place/RL_agent_util.cpp b/vpr/src/place/RL_agent_util.cpp index 66352786a1d..b749a39c4cd 100644 --- a/vpr/src/place/RL_agent_util.cpp +++ b/vpr/src/place/RL_agent_util.cpp @@ -1,6 +1,7 @@ #include "RL_agent_util.h" +#include "manual_move_generator.h" -void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, const t_placer_opts& placer_opts, int move_lim) { +void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, std::unique_ptr& manual_move_generator, const t_placer_opts& placer_opts, int move_lim) { if (placer_opts.RL_agent_placement == false) { if (placer_opts.place_algorithm.is_timing_driven()) { VTR_LOG("Using static probabilities for choosing each move type\n"); @@ -13,6 +14,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: VTR_LOG("Probability of Critical_uniform_move : %f \n", placer_opts.place_static_move_prob[6]); move_generator = std::make_unique(placer_opts.place_static_move_prob); move_generator2 = std::make_unique(placer_opts.place_static_move_prob); + //manual_move_generator = std::make_unique(placer_opts.place_static_move_prob); } else { //Non-timing driven placement VTR_LOG("Using static probabilities for choosing each move type\n"); VTR_LOG("Probability of Uniform_move : %f \n", placer_opts.place_static_notiming_move_prob[0]); @@ -20,6 +22,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: VTR_LOG("Probability of Centroid_move : %f \n", placer_opts.place_static_notiming_move_prob[2]); move_generator = std::make_unique(placer_opts.place_static_notiming_move_prob); move_generator2 = std::make_unique(placer_opts.place_static_notiming_move_prob); + //manual_move_generator = std::make_unique(placer_opts.place_static_notiming_move_prob); } } else { //RL based placement /* For the non timing driven placecment: the agent has a single state * @@ -42,6 +45,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: karmed_bandit_agent1 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent1); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_MOVE_TYPES, placer_opts.place_agent_epsilon); @@ -52,6 +56,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: karmed_bandit_agent1 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent1); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); @@ -67,6 +72,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: karmed_bandit_agent1 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent1); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_MOVE_TYPES); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); @@ -76,6 +82,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: karmed_bandit_agent1 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent1); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); diff --git a/vpr/src/place/RL_agent_util.h b/vpr/src/place/RL_agent_util.h index 5b23cf464d3..bb52b4e365f 100644 --- a/vpr/src/place/RL_agent_util.h +++ b/vpr/src/place/RL_agent_util.h @@ -3,6 +3,7 @@ #include "static_move_generator.h" #include "simpleRL_move_generator.h" +#include "manual_move_generator.h" //enum represents the available agent states enum e_agent_state { @@ -18,7 +19,7 @@ enum e_agent_state { * It returns a unique pointer for each move generator in move_generator and move_generator2 * move_lim: represents the num of moves per temp. */ -void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, const t_placer_opts& placer_opts, int move_lim); +void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, std::unique_ptr& manual_move_generator, const t_placer_opts& placer_opts, int move_lim); /** * @brief copy one of the available move_generators to be the current move_generator that would be used in the placement based on the placer_options and the agent state diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index dfca1c6a322..e1c93ffb991 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -3,8 +3,32 @@ #ifndef NO_GRAPHICS +ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + + karmed_bandit_agent = std::move(agent); +} + +ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + avail_moves.push_back(std::move(std::make_unique())); + + karmed_bandit_agent = std::move(agent); +} + //Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected) { +e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { ManualMovesGlobals* manual_move_global = get_manual_moves_global(); int block_id = manual_move_global->manual_move_info.blockID; t_pl_loc to = manual_move_global->manual_move_info.to_location; diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index fdfce4c1181..2285cccb367 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -11,14 +11,22 @@ # include "uniform_move_generator.h" # include "critical_uniform_move_generator.h" # include "centroid_move_generator.h" +# include "simpleRL_move_generator.h" # include /** Manual Moves Generator, inherits from MoveGenerator class **/ class ManualMoveGenerator : public MoveGenerator { + private: + std::vector> avail_moves; // list of pointers to the available move generators (the different move types) + std::unique_ptr karmed_bandit_agent; // a pointer to the specific agent used (e.g. Softmax) + public: + // constructors using a pointer to the agent used + ManualMoveGenerator(std::unique_ptr& agent); + ManualMoveGenerator(std::unique_ptr& agent); + //Evaluates if move is successful and legal or unable to do. - using MoveGenerator::propose_move; - e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected); + e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/); }; #endif /*NO_GRAPHICS*/ diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 07d0562bafe..7dff6ffb677 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -63,15 +63,13 @@ * -1*(1.5-REWARD_BB_TIMING_RELATIVE_WEIGHT)*timing_cost + (1+REWARD_BB_TIMING_RELATIVE_WEIGHT)*bb_cost) */ -#ifndef NO_GRAPHICS - -# define REWARD_BB_TIMING_RELATIVE_WEIGHT 0.4 +#define REWARD_BB_TIMING_RELATIVE_WEIGHT 0.4 -# ifdef VTR_ENABLE_DEBUG_LOGGING -# include "draw_types.h" -# include "draw_global.h" -# include "draw_color.h" -# endif +#ifdef VTR_ENABLE_DEBUG_LOGGING +# include "draw_types.h" +# include "draw_global.h" +# include "draw_color.h" +#endif using std::max; using std::min; @@ -80,18 +78,18 @@ using std::min; /* This defines the error tolerance for floating points variables used in * * cost computation. 0.01 means that there is a 1% error tolerance. */ -# define ERROR_TOL .01 +#define ERROR_TOL .01 /* This defines the maximum number of swap attempts before invoking the * * once-in-a-while placement legality check as well as floating point * * variables round-offs check. */ -# define MAX_MOVES_BEFORE_RECOMPUTE 500000 +#define MAX_MOVES_BEFORE_RECOMPUTE 500000 /* Flags for the states of the bounding box. * * Stored as char for memory efficiency. */ -# define NOT_UPDATED_YET 'N' -# define UPDATED_ONCE 'U' -# define GOT_FROM_SCRATCH 'S' +#define NOT_UPDATED_YET 'N' +#define UPDATED_ONCE 'U' +#define GOT_FROM_SCRATCH 'S' /* For comp_cost. NORMAL means use the method that generates updateable * * bounding boxes for speed. CHECK means compute all bounding boxes from * @@ -166,82 +164,82 @@ static const float cross_count[50] = {/* [0..49] */ 1.0, 1.0, 1.0, 1.0828, std::unique_ptr f_move_stats_file(nullptr, vtr::fclose); -# ifdef VTR_ENABLE_DEBUG_LOGGIING -# define LOG_MOVE_STATS_HEADER() \ - do { \ - if (f_move_stats_file) { \ - fprintf(f_move_stats_file.get(), \ - "temp,from_blk,to_blk,from_type,to_type," \ - "blk_count," \ - "delta_cost,delta_bb_cost,delta_td_cost," \ - "outcome,reason\n"); \ - } \ - } while (false) - -# define LOG_MOVE_STATS_PROPOSED(t, affected_blocks) \ - do { \ - if (f_move_stats_file) { \ - auto& place_ctx = g_vpr_ctx.placement(); \ - auto& cluster_ctx = g_vpr_ctx.clustering(); \ - ClusterBlockId b_from = affected_blocks.moved_blocks[0].block_num; \ - \ - t_pl_loc to = affected_blocks.moved_blocks[0].new_loc; \ - ClusterBlockId b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; \ - \ - t_logical_block_type_ptr from_type = cluster_ctx.clb_nlist.block_type(b_from); \ - t_logical_block_type_ptr to_type = nullptr; \ - if (b_to) { \ - to_type = cluster_ctx.clb_nlist.block_type(b_to); \ - } \ - \ - fprintf(f_move_stats_file.get(), \ - "%g," \ - "%d,%d," \ - "%s,%s," \ - "%d,", \ - t, \ - int(size_t(b_from)), int(size_t(b_to)), \ - from_type->name, (to_type ? to_type->name : "EMPTY"), \ - affected_blocks.num_moved_blocks); \ - } \ - } while (false) - -# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ - outcome, reason) \ - do { \ - if (f_move_stats_file) { \ - fprintf(f_move_stats_file.get(), \ - "%g,%g,%g," \ - "%s,%s\n", \ - delta_cost, delta_bb_cost, delta_td_cost, \ - outcome, reason); \ - } \ - } while (false) - -# else - -# define LOG_MOVE_STATS_HEADER() \ - do { \ - fprintf(f_move_stats_file.get(), \ - "VTR_ENABLE_DEBUG_LOGGING disabled " \ - "-- No move stats recorded\n"); \ - } while (false) - -# define LOG_MOVE_STATS_PROPOSED(t, blocks_affected) \ - do { \ - } while (false) - -# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ - outcome, reason) \ - do { \ - } while (false) - -# endif +#ifdef VTR_ENABLE_DEBUG_LOGGIING +# define LOG_MOVE_STATS_HEADER() \ + do { \ + if (f_move_stats_file) { \ + fprintf(f_move_stats_file.get(), \ + "temp,from_blk,to_blk,from_type,to_type," \ + "blk_count," \ + "delta_cost,delta_bb_cost,delta_td_cost," \ + "outcome,reason\n"); \ + } \ + } while (false) + +# define LOG_MOVE_STATS_PROPOSED(t, affected_blocks) \ + do { \ + if (f_move_stats_file) { \ + auto& place_ctx = g_vpr_ctx.placement(); \ + auto& cluster_ctx = g_vpr_ctx.clustering(); \ + ClusterBlockId b_from = affected_blocks.moved_blocks[0].block_num; \ + \ + t_pl_loc to = affected_blocks.moved_blocks[0].new_loc; \ + ClusterBlockId b_to = place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile]; \ + \ + t_logical_block_type_ptr from_type = cluster_ctx.clb_nlist.block_type(b_from); \ + t_logical_block_type_ptr to_type = nullptr; \ + if (b_to) { \ + to_type = cluster_ctx.clb_nlist.block_type(b_to); \ + } \ + \ + fprintf(f_move_stats_file.get(), \ + "%g," \ + "%d,%d," \ + "%s,%s," \ + "%d,", \ + t, \ + int(size_t(b_from)), int(size_t(b_to)), \ + from_type->name, (to_type ? to_type->name : "EMPTY"), \ + affected_blocks.num_moved_blocks); \ + } \ + } while (false) + +# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ + outcome, reason) \ + do { \ + if (f_move_stats_file) { \ + fprintf(f_move_stats_file.get(), \ + "%g,%g,%g," \ + "%s,%s\n", \ + delta_cost, delta_bb_cost, delta_td_cost, \ + outcome, reason); \ + } \ + } while (false) + +#else + +# define LOG_MOVE_STATS_HEADER() \ + do { \ + fprintf(f_move_stats_file.get(), \ + "VTR_ENABLE_DEBUG_LOGGING disabled " \ + "-- No move stats recorded\n"); \ + } while (false) + +# define LOG_MOVE_STATS_PROPOSED(t, blocks_affected) \ + do { \ + } while (false) + +# define LOG_MOVE_STATS_OUTCOME(delta_cost, delta_bb_cost, delta_td_cost, \ + outcome, reason) \ + do { \ + } while (false) + +#endif /********************* Static subroutines local to place.c *******************/ -# ifdef VERBOSE +#ifdef VERBOSE static void print_clb_placement(const char* fname); -# endif +#endif static void alloc_and_load_placement_structs(float place_cost_exp, const t_placer_opts& placer_opts, @@ -491,7 +489,7 @@ void try_place(const t_placer_opts& placer_opts, * pow(cluster_ctx.clb_nlist.blocks().size(), 1.3333)); //create the move generator based on the chosen strategy - create_move_generators(move_generator, move_generator2, placer_opts, + create_move_generators(move_generator, move_generator2, manual_move_generator, placer_opts, move_lim); width_fac = placer_opts.place_chan_width; @@ -506,7 +504,7 @@ void try_place(const t_placer_opts& placer_opts, initial_placement(placer_opts.pad_loc_type, placer_opts.constraints_file.c_str()); -# ifdef ENABLE_ANALYTIC_PLACE +#ifdef ENABLE_ANALYTIC_PLACE /* * Analytic Placer: * Passes in the initial_placement via vpr_context, and passes its placement back via locations marked on @@ -516,7 +514,7 @@ void try_place(const t_placer_opts& placer_opts, if (placer_opts.enable_analytic_placer) { AnalyticPlacer{}.ap_place(); } -# endif /* ENABLE_ANALYTIC_PLACE */ +#endif /* ENABLE_ANALYTIC_PLACE */ // Update physical pin values for (auto block_id : cluster_ctx.clb_nlist.blocks()) { @@ -731,12 +729,12 @@ void try_place(const t_placer_opts& placer_opts, bool skip_anneal = false; -# ifdef ENABLE_ANALYTIC_PLACE +#ifdef ENABLE_ANALYTIC_PLACE // Analytic placer: When enabled, skip most of the annealing and go straight to quench // TODO: refactor goto label. if (placer_opts.enable_analytic_placer) skip_anneal = true; -# endif /* ENABLE_ANALYTIC_PLACE */ +#endif /* ENABLE_ANALYTIC_PLACE */ //RL agent state definition e_agent_state agent_state = EARLY_IN_THE_ANNEAL; @@ -812,11 +810,11 @@ void try_place(const t_placer_opts& placer_opts, update_screen(ScreenUpdatePriority::MINOR, msg, PLACEMENT, timing_info); -# ifdef VERBOSE +#ifdef VERBOSE if (getEchoEnabled()) { print_clb_placement("first_iteration_clb_placement.echo"); } -# endif +#endif } while (state.outer_loop_update(stats.success_rate, costs, placer_opts, annealing_sched)); /* Outer loop of the simmulated annealing ends */ @@ -899,11 +897,11 @@ void try_place(const t_placer_opts& placer_opts, // TODO: // 1. add some subroutine hierarchy! Too big! -# ifdef VERBOSE +#ifdef VERBOSE if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_END_CLB_PLACEMENT)) { print_clb_placement(getEchoFileName(E_ECHO_END_CLB_PLACEMENT)); } -# endif +#endif check_place(costs, place_delay_model.get(), placer_criticalities.get(), placer_opts.place_algorithm); @@ -989,9 +987,9 @@ static void outer_loop_update_timing_info(const t_placer_opts& placer_opts, /*for normalizing the tradeoff between timing and wirelength (bb) */ if (*outer_crit_iter_count >= placer_opts.recompute_crit_iter || placer_opts.inner_loop_recompute_divider != 0) { -# ifdef VERBOSE +#ifdef VERBOSE VTR_LOG("Outer loop recompute criticalities\n"); -# endif +#endif num_connections = std::max(num_connections, 1); //Avoid division by zero VTR_ASSERT(num_connections > 0); @@ -1062,9 +1060,9 @@ static void placement_inner_loop(const t_annealing_state* state, && inner_iter != state->move_lim - 1) { /*on last iteration don't recompute */ inner_crit_iter_count = 0; -# ifdef VERBOSE +#ifdef VERBOSE VTR_LOG("Inner loop recompute criticalities\n"); -# endif +#endif PlaceCritParams crit_params; crit_params.crit_exponent = state->crit_exponent; @@ -1077,13 +1075,13 @@ static void placement_inner_loop(const t_annealing_state* state, } inner_crit_iter_count++; } -# ifdef VERBOSE +#ifdef VERBOSE VTR_LOG("t = %g cost = %g bb_cost = %g timing_cost = %g move = %d\n", t, costs->cost, costs->bb_cost, costs->timing_cost, inner_iter); if (fabs((costs->bb_cost) - comp_bb_cost(CHECK)) > (costs->bb_cost) * ERROR_TOL) VPR_ERROR(VPR_ERROR_PLACE, "fabs((*bb_cost) - comp_bb_cost(CHECK)) > (*bb_cost) * ERROR_TOL"); -# endif +#endif /* Lines below prevent too much round-off error from accumulating * in the cost over many iterations (due to incremental updates). @@ -1219,10 +1217,10 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t num_accepted, move_lim); } -# ifdef VERBOSE +#ifdef VERBOSE /* Print stats related to finding the initital temp. */ VTR_LOG("std_dev: %g, average cost: %g, starting temp: %g\n", std_dev, av, 20. * std_dev); -# endif +#endif /* Set the initial temperature to 20 times the standard of deviation */ /* so that the initial temperature adjusts according to the circuit */ @@ -1327,18 +1325,18 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; - //#ifndef NO_GRAPHICS +#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - create_move_outcome = manual_move_generator.propose_move(blocks_affected); + create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } - //#endif /*NO_GRAPHICS*/ +#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1424,7 +1422,7 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); - //#ifndef NO_GRAPHICS +#ifndef NO_GRAPHICS if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); @@ -1432,7 +1430,7 @@ static e_move_result try_swap(const t_annealing_state* state, //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } - //#endif /*NO_GRAPHICS*/ +#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; @@ -1470,9 +1468,9 @@ static e_move_result try_swap(const t_annealing_state* state, ++move_type_stat.accepted_moves[(int)move_type]; //Highlights the new block when manual move is selected. - //#ifndef NO_GRAPHICS +#ifndef NO_GRAPHICS highlight_new_block_location(manual_move_global->manual_move_flag); - //#endif /*NO_GRPAHICS*/ +#endif /*NO_GRPAHICS*/ } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); @@ -1528,20 +1526,20 @@ static e_move_result try_swap(const t_annealing_state* state, calculate_reward_and_process_outcome(placer_opts, move_outcome_stats, delta_c, timing_bb_factor, move_generator); -# ifdef VTR_ENABLE_DEBUG_LOGGING -# ifndef NO_GRAPHICS +#ifdef VTR_ENABLE_DEBUG_LOGGING +# ifndef NO_GRAPHICS stop_placement_and_check_breakpoints(blocks_affected, move_outcome, delta_c, bb_delta_c, timing_delta_c); -# endif # endif +#endif /* Clear the data structure containing block move info */ clear_move_blocks(blocks_affected); //VTR_ASSERT(check_macro_placement_consistency() == 0); -# if 0 +#if 0 //Check that each accepted swap yields a valid placement check_place(*costs, delay_model, place_algorithm); -# endif +#endif return move_outcome; } @@ -1899,9 +1897,9 @@ static void commit_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { //Reverts modifications to proposed_connection_delay and proposed_connection_timing_cost based on //the move proposed in blocks_affected static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { -# ifndef VTR_ASSERT_SAFE_ENABLED +#ifndef VTR_ASSERT_SAFE_ENABLED static_cast(blocks_affected); -# else +#else //Invalidate temp delay & timing cost values to match sanity checks in //comp_td_connection_cost() auto& cluster_ctx = g_vpr_ctx.clustering(); @@ -1917,7 +1915,7 @@ static void revert_td_cost(const t_pl_blocks_to_be_moved& blocks_affected) { proposed_connection_delay[net][ipin] = INVALID_DELAY; proposed_connection_timing_cost[net][ipin] = INVALID_DELAY; } -# endif +#endif } /** @@ -2823,7 +2821,7 @@ int check_macro_placement_consistency() { return error; } -# ifdef VERBOSE +#ifdef VERBOSE static void print_clb_placement(const char* fname) { /* Prints out the clb placements to a file. */ FILE* fp; @@ -2840,7 +2838,7 @@ static void print_clb_placement(const char* fname) { fclose(fp); } -# endif +#endif static void free_try_swap_arrays() { g_vpr_ctx.mutable_placement().compressed_block_grids.clear(); @@ -2865,7 +2863,7 @@ static void generate_post_place_timing_reports(const t_placer_opts& placer_opts, *timing_info.setup_analyzer(), analysis_opts.timing_report_npaths); } -# if 0 +#if 0 static void update_screen_debug(); //Performs a major (i.e. interactive) placement screen update. @@ -2874,7 +2872,7 @@ static void update_screen_debug(); static void update_screen_debug() { update_screen(ScreenUpdatePriority::MAJOR, "DEBUG", PLACEMENT, nullptr); } -# endif +#endif static void print_place_status_header() { VTR_LOG( @@ -3035,5 +3033,3 @@ static void calculate_reward_and_process_outcome( bool placer_needs_lookahead(const t_vpr_setup& vpr_setup) { return (vpr_setup.PlacerOpts.place_algorithm.is_timing_driven()); } - -#endif /*NO_GRAPHICS*/ From db883b5bab6a548f7d2113d2261e394a09513f48 Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 13:48:21 -0400 Subject: [PATCH 22/46] Deleted timer class used for testing and disbaled NO_GRAPHICS code for manual move generator file --- vpr/src/draw/manual_moves.cpp | 50 ++++++++++++------------- vpr/src/draw/manual_moves.h | 27 ------------- vpr/src/place/manual_move_generator.cpp | 4 -- vpr/src/place/place.cpp | 10 ++--- 4 files changed, 27 insertions(+), 64 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 59d0a8b261a..22179ed2af3 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -6,11 +6,11 @@ #include "buttons.h" #include "move_utils.h" -#ifndef NO_GRAPHICS - //Global Variables ManualMovesGlobals manual_moves_global; +#ifndef NO_GRAPHICS + void draw_manual_moves_window(std::string block_id) { if (!manual_moves_global.mm_window_is_open) { manual_moves_global.mm_window_is_open = true; @@ -177,26 +177,12 @@ bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { return true; } -bool string_is_a_number(std::string block_id) { - for (size_t i = 0; i < block_id.size(); i++) { - //Returns 0 if the string does not have characters from 0-9 - if (isdigit(block_id[i]) == 0) { - return false; - } - } - return true; -} - void get_manual_move_flag() { GObject* manual_moves = application.get_object("manualMove"); //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); } -ManualMovesGlobals* get_manual_moves_global() { - return &manual_moves_global; -} - void cost_summary_dialog() { GtkWidget* dialog; GtkWidget* content_area; @@ -280,6 +266,19 @@ void highlight_new_block_location(bool manual_move_flag) { } } +//Manual move window turns false, the window is destroyed. +void close_manual_moves_window() { + manual_moves_global.mm_window_is_open = false; +} + +#endif /*NO_GRAPHICS*/ + +/**** NO_GRAPHICS functions ****/ + +ManualMovesGlobals* get_manual_moves_global() { + return &manual_moves_global; +} + //Updates ManualMovesInfo cost members void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { manual_moves_global.manual_move_info.delta_cost = d_cost; @@ -288,15 +287,12 @@ void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_ manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; } -//Manual move window turns false, the window is destroyed. -void close_manual_moves_window() { - manual_moves_global.mm_window_is_open = false; -} - -//Deactivates the toggle button once the windows close. -void deactivating_toggle_button() { - GObject* manual_move_toggle = application.get_object("manualMove"); - gtk_toggle_button_set_active((GtkToggleButton*)manual_move_toggle, FALSE); +bool string_is_a_number(std::string block_id) { + for (size_t i = 0; i < block_id.size(); i++) { + //Returns 0 if the string does not have characters from 0-9 + if (isdigit(block_id[i]) == 0) { + return false; + } + } + return true; } - -#endif diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index cbd780e8d2c..bb425a0a9cf 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -49,31 +49,6 @@ struct ManualMovesGlobals { bool manual_move_flag = false; }; -class Timer { - public: - Timer() { - m_StartTimepoint = std::chrono::high_resolution_clock::now(); - } - ~Timer() { - Stop(); - } - void Stop() { - auto endTimepoint = std::chrono::high_resolution_clock::now(); - - auto start = std::chrono::time_point_cast(m_StartTimepoint).time_since_epoch().count(); - auto end = std::chrono::time_point_cast(endTimepoint).time_since_epoch().count(); - - auto duration = end - start; - double ms = duration * 0.001; - double s = duration * 0.000001; - - std::cout << duration << "us -- " << ms << "ms -- " << s << "s\n"; - } - - private: - std::chrono::time_point m_StartTimepoint; -}; - /** manual moves functions **/ void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); @@ -86,8 +61,6 @@ ManualMovesGlobals* get_manual_moves_global(); void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); void highlight_new_block_location(bool manual_move_flag); -void deactivating_toggle_button(); - #endif /*NO_GRAPHICS */ #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index e1c93ffb991..103f87b7d24 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -1,8 +1,6 @@ #include "manual_move_generator.h" #include "manual_moves.h" -#ifndef NO_GRAPHICS - ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { avail_moves.push_back(std::move(std::make_unique())); avail_moves.push_back(std::move(std::make_unique())); @@ -63,5 +61,3 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; } - -#endif diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 7dff6ffb677..ae62c124fcd 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1325,18 +1325,17 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; -#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { +#ifndef NO_GRAPHICS draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - +#endif /*NO_GRAPHICS*/ create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } -#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1422,15 +1421,14 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); -#ifndef NO_GRAPHICS if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); +#ifndef NO_GRAPHICS cost_summary_dialog(); - +#endif /*NO_GRAPHICS*/ //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } -#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; From d19dede61e515c42de64501754600d4249372833 Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 14:00:39 -0400 Subject: [PATCH 23/46] Changed position of NO_GRAPHICS in place.cpp --- vpr/src/place/place.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index ae62c124fcd..8e99cc326bd 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1181,10 +1181,10 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t (int)cluster_ctx.clb_nlist.blocks().size()); for (int i = 0; i < move_lim; i++) { - //#ifndef NO_GRAPHICS +#ifndef NO_GRAPHICS //Checks manual move flag for manual move feature get_manual_move_flag(); - //#endif /*NO_GRAPHICS*/ +#endif /*NO_GRAPHICS*/ //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack e_move_result swap_result = try_swap(state, costs, move_generator, From fe60cb07762075427615a2d53987ef95ce4f8407 Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 14:28:48 -0400 Subject: [PATCH 24/46] Changed NO_GRAPHICS in manual move. Should be able to compile now --- vpr/src/draw/manual_moves.cpp | 10 ++++------ vpr/src/place/manual_move_generator.cpp | 3 +++ vpr/src/place/place.cpp | 9 +++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 22179ed2af3..004fd86aee2 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -6,11 +6,11 @@ #include "buttons.h" #include "move_utils.h" +#ifndef NO_GRAPHICS + //Global Variables ManualMovesGlobals manual_moves_global; -#ifndef NO_GRAPHICS - void draw_manual_moves_window(std::string block_id) { if (!manual_moves_global.mm_window_is_open) { manual_moves_global.mm_window_is_open = true; @@ -271,10 +271,6 @@ void close_manual_moves_window() { manual_moves_global.mm_window_is_open = false; } -#endif /*NO_GRAPHICS*/ - -/**** NO_GRAPHICS functions ****/ - ManualMovesGlobals* get_manual_moves_global() { return &manual_moves_global; } @@ -296,3 +292,5 @@ bool string_is_a_number(std::string block_id) { } return true; } + +#endif /*NO_GRAPHICS*/ diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 103f87b7d24..68f165ffc5e 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -27,9 +27,12 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag //Manual Move Generator function e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { +#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); int block_id = manual_move_global->manual_move_info.blockID; t_pl_loc to = manual_move_global->manual_move_info.to_location; +#endif /*NO_GRAPHICS*/ + ClusterBlockId b_from = ClusterBlockId(block_id); //Checking if the block was found diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 8e99cc326bd..0ab865eb872 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1325,17 +1325,17 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; +#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { -#ifndef NO_GRAPHICS draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); -#endif /*NO_GRAPHICS*/ create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } +#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1421,14 +1421,15 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); +#ifndef NO_GRAPHICS if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); -#ifndef NO_GRAPHICS cost_summary_dialog(); -#endif /*NO_GRAPHICS*/ + //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } +#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; From 11fd6aede9e0ee84b5742236f8dcba360c26f1ac Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 15:32:14 -0400 Subject: [PATCH 25/46] Removed NO_GRAPHICS from the manual move generator.h --- vpr/src/place/manual_move_generator.h | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index 2285cccb367..aebce85e4ec 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -1,18 +1,16 @@ #ifndef VPR_MANUAL_MOVE_GEN_H #define VPR_MANUAL_MOVE_GEN_H -#ifndef NO_GRAPHICS - -# include "move_generator.h" -# include "median_move_generator.h" -# include "weighted_median_move_generator.h" -# include "weighted_centroid_move_generator.h" -# include "feasible_region_move_generator.h" -# include "uniform_move_generator.h" -# include "critical_uniform_move_generator.h" -# include "centroid_move_generator.h" -# include "simpleRL_move_generator.h" -# include +#include "move_generator.h" +#include "median_move_generator.h" +#include "weighted_median_move_generator.h" +#include "weighted_centroid_move_generator.h" +#include "feasible_region_move_generator.h" +#include "uniform_move_generator.h" +#include "critical_uniform_move_generator.h" +#include "centroid_move_generator.h" +#include "simpleRL_move_generator.h" +#include /** Manual Moves Generator, inherits from MoveGenerator class **/ class ManualMoveGenerator : public MoveGenerator { @@ -29,6 +27,4 @@ class ManualMoveGenerator : public MoveGenerator { e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/); }; -#endif /*NO_GRAPHICS*/ - #endif /*VPR_MANUAL_MOVE_GEN_H */ From 0f8a85e9ba83e6c809e5b9af3fe0f83973b4c4ef Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 17:58:54 -0400 Subject: [PATCH 26/46] Changes for Basic with nO_GRAPHICS test --- vpr/src/draw/manual_moves.cpp | 10 +++-- vpr/src/draw/manual_moves.h | 53 +++++++++++++------------ vpr/src/place/manual_move_generator.cpp | 2 - vpr/src/place/place.cpp | 9 ++--- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 004fd86aee2..998bbaafbc5 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -6,11 +6,11 @@ #include "buttons.h" #include "move_utils.h" -#ifndef NO_GRAPHICS - //Global Variables ManualMovesGlobals manual_moves_global; +#ifndef NO_GRAPHICS + void draw_manual_moves_window(std::string block_id) { if (!manual_moves_global.mm_window_is_open) { manual_moves_global.mm_window_is_open = true; @@ -271,6 +271,10 @@ void close_manual_moves_window() { manual_moves_global.mm_window_is_open = false; } +#endif /*NO_GRAPHICS*/ + +/*NO_GRAPHICS FUNCTIONS: */ + ManualMovesGlobals* get_manual_moves_global() { return &manual_moves_global; } @@ -292,5 +296,3 @@ bool string_is_a_number(std::string block_id) { } return true; } - -#endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index bb425a0a9cf..dcb3721c655 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -2,30 +2,28 @@ #define MANUAL_MOVES_H /** This file contains all functions for manual moves **/ -#ifndef NO_GRAPHICS - -# include "draw_global.h" -# include "draw_global.h" -# include "move_utils.h" -# include "move_generator.h" -# include "ezgl/application.hpp" -# include "ezgl/graphics.hpp" -# include "median_move_generator.h" -# include "weighted_median_move_generator.h" -# include "weighted_centroid_move_generator.h" -# include "feasible_region_move_generator.h" -# include "uniform_move_generator.h" -# include "critical_uniform_move_generator.h" -# include "centroid_move_generator.h" +#include "draw_global.h" +#include "draw_global.h" +#include "move_utils.h" +#include "move_generator.h" +#include "ezgl/application.hpp" +#include "ezgl/graphics.hpp" +#include "median_move_generator.h" +#include "weighted_median_move_generator.h" +#include "weighted_centroid_move_generator.h" +#include "feasible_region_move_generator.h" +#include "uniform_move_generator.h" +#include "critical_uniform_move_generator.h" +#include "centroid_move_generator.h" -# include -# include -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include +#include +#include struct ManualMovesInfo { int blockID = -1; @@ -49,18 +47,21 @@ struct ManualMovesGlobals { bool manual_move_flag = false; }; +#ifndef NO_GRAPHICS + /** manual moves functions **/ void draw_manual_moves_window(std::string block_id); void close_manual_moves_window(); void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to); -bool string_is_a_number(std::string block_id); void get_manual_move_flag(); void cost_summary_dialog(); -ManualMovesGlobals* get_manual_moves_global(); -void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); void highlight_new_block_location(bool manual_move_flag); #endif /*NO_GRAPHICS */ +ManualMovesGlobals* get_manual_moves_global(); +void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); +bool string_is_a_number(std::string block_id); + #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 68f165ffc5e..8e6175df271 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -27,11 +27,9 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag //Manual Move Generator function e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { -#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); int block_id = manual_move_global->manual_move_info.blockID; t_pl_loc to = manual_move_global->manual_move_info.to_location; -#endif /*NO_GRAPHICS*/ ClusterBlockId b_from = ClusterBlockId(block_id); diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 0ab865eb872..8e99cc326bd 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1325,17 +1325,17 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; -#ifndef NO_GRAPHICS ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { +#ifndef NO_GRAPHICS draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); +#endif /*NO_GRAPHICS*/ create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } -#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1421,15 +1421,14 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); -#ifndef NO_GRAPHICS if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); +#ifndef NO_GRAPHICS cost_summary_dialog(); - +#endif /*NO_GRAPHICS*/ //User accepts or rejects the move. move_outcome = manual_move_global->manual_move_info.user_move_outcome; } -#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; From e5266efcb7e620c230c4b6f2d16720e4921ee887 Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 18:32:24 -0400 Subject: [PATCH 27/46] Put guards around include libraries in manul move.h --- vpr/src/draw/manual_moves.h | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index dcb3721c655..d0f6ea76a59 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -2,28 +2,23 @@ #define MANUAL_MOVES_H /** This file contains all functions for manual moves **/ -#include "draw_global.h" -#include "draw_global.h" -#include "move_utils.h" -#include "move_generator.h" -#include "ezgl/application.hpp" -#include "ezgl/graphics.hpp" -#include "median_move_generator.h" -#include "weighted_median_move_generator.h" -#include "weighted_centroid_move_generator.h" -#include "feasible_region_move_generator.h" -#include "uniform_move_generator.h" -#include "critical_uniform_move_generator.h" -#include "centroid_move_generator.h" -#include -#include -#include -#include -#include -#include -#include -#include +#ifndef NO_GRAPHICS + +# include "draw_global.h" +# include "draw_global.h" +# include "move_utils.h" +# include "ezgl/application.hpp" +# include "ezgl/graphics.hpp" + +# include +# include +# include +# include +# include +# include + +#endif /*NO_GRAPHICS*/ struct ManualMovesInfo { int blockID = -1; From 0ad8714fa9ac44d67b0adc5c2c704e45f25cdc46 Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 16 Jul 2021 19:32:38 -0400 Subject: [PATCH 28/46] Moved move_utils.h header file in manual move.h --- vpr/src/draw/manual_moves.cpp | 4 +--- vpr/src/draw/manual_moves.h | 23 ++++++++++++----------- vpr/src/place/manual_move_generator.cpp | 1 - vpr/src/place/place.cpp | 1 + 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 998bbaafbc5..2ccd11524cd 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -2,9 +2,7 @@ #include "move_utils.h" #include "globals.h" #include "draw.h" -#include "move_generator.h" #include "buttons.h" -#include "move_utils.h" //Global Variables ManualMovesGlobals manual_moves_global; @@ -273,7 +271,7 @@ void close_manual_moves_window() { #endif /*NO_GRAPHICS*/ -/*NO_GRAPHICS FUNCTIONS: */ +/**NO_GRAPHICS FUNCTIONS**/ ManualMovesGlobals* get_manual_moves_global() { return &manual_moves_global; diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index d0f6ea76a59..c2ac184193c 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -2,24 +2,23 @@ #define MANUAL_MOVES_H /** This file contains all functions for manual moves **/ - #ifndef NO_GRAPHICS # include "draw_global.h" # include "draw_global.h" -# include "move_utils.h" # include "ezgl/application.hpp" # include "ezgl/graphics.hpp" -# include -# include -# include -# include -# include -# include - #endif /*NO_GRAPHICS*/ +#include "move_utils.h" +#include +#include +#include +#include +#include +#include + struct ManualMovesInfo { int blockID = -1; int x_pos = -1; @@ -36,10 +35,12 @@ struct ManualMovesInfo { struct ManualMovesGlobals { ManualMovesInfo manual_move_info; - GtkWidget* manual_move_window; bool mm_window_is_open = false; bool user_highlighted_block = false; bool manual_move_flag = false; +#ifndef NO_GRAPHICS + GtkWidget* manual_move_window; +#endif /*NO_GRAPHICS*/ }; #ifndef NO_GRAPHICS @@ -53,7 +54,7 @@ void get_manual_move_flag(); void cost_summary_dialog(); void highlight_new_block_location(bool manual_move_flag); -#endif /*NO_GRAPHICS */ +#endif /*NO_GRAPHICS*/ ManualMovesGlobals* get_manual_moves_global(); void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 8e6175df271..103f87b7d24 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -30,7 +30,6 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ ManualMovesGlobals* manual_move_global = get_manual_moves_global(); int block_id = manual_move_global->manual_move_info.blockID; t_pl_loc to = manual_move_global->manual_move_info.to_location; - ClusterBlockId b_from = ClusterBlockId(block_id); //Checking if the block was found diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 8e99cc326bd..b903dabde97 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1331,6 +1331,7 @@ static e_move_result try_swap(const t_annealing_state* state, draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); #endif /*NO_GRAPHICS*/ + create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } else { //Generate a new move (perturbation) used to explore the space of possible placements From 8fcac35542b7e079a0926b8067bf0b58adc9312e Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 19 Jul 2021 14:54:18 -0400 Subject: [PATCH 29/46] Commented all the files with manual move code --- vpr/src/draw/manual_moves.cpp | 9 +++ vpr/src/draw/manual_moves.h | 94 ++++++++++++++++++++++++- vpr/src/place/manual_move_generator.cpp | 7 ++ vpr/src/place/manual_move_generator.h | 15 +++- vpr/src/place/place.cpp | 2 + 5 files changed, 122 insertions(+), 5 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 2ccd11524cd..1c67eef4d4c 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -1,3 +1,12 @@ +/* + * @file manual_moves.cpp + * @author Paula Perdomo + * @date 2021-07-19 + * @brief Contains the function definitions needed for manual moves feature. + * + * Includes the graphics/gtk function for manual moves. The Manual Move Generator class is defined manual_move_generator.h/cpp. + */ + #include "manual_moves.h" #include "move_utils.h" #include "globals.h" diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index c2ac184193c..b5b9a668ac4 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -1,3 +1,12 @@ +/* + * @file manual_moves.h + * @author Paula Perdomo + * @date 2021-07-19 + * @brief Contains the function prototypes needed for manual moves feature. + * + * Includes the data structures sed and gtk function for manual moves. The Manual Move Generator class is defined manual_move_generator.h/cpp. + */ + #ifndef MANUAL_MOVES_H #define MANUAL_MOVES_H @@ -19,6 +28,12 @@ #include #include +/** + * @brief ManualMovesInfo struct + * + * Contains information about the block, location, validity of user input, timing variables, and placer outcomes. + */ + struct ManualMovesInfo { int blockID = -1; int x_pos = -1; @@ -33,6 +48,12 @@ struct ManualMovesInfo { e_move_result user_move_outcome = ABORTED; }; +/** + * @brief ManualMovesGlobals struct + * + * Contains a ManualMovesInfo variable to store manual move data, boolean values to check the state of the windows needed and gtk manual move widow variable. + */ + struct ManualMovesGlobals { ManualMovesInfo manual_move_info; bool mm_window_is_open = false; @@ -46,18 +67,85 @@ struct ManualMovesGlobals { #ifndef NO_GRAPHICS /** manual moves functions **/ + + +/** + * @brief Gets the state of the manual moves togle button and assigns it to the manual_move_flag in the ManualMovesGlobal struct. + */ +void get_manual_move_flag(); + +/** + * @brief Gets the manual_moves_global variables in manual_move.cpp. + * + * @return The manual_moves_global variable. + */ +ManualMovesGlobals* get_manual_moves_global(); + +/** + * @brief Draws the manual move window. + * + * Window prompts the user for input: block id/name, s position, y position, and subtile position. + * @param block_id: The block id selected/highlighted by the user. + */ void draw_manual_moves_window(std::string block_id); -void close_manual_moves_window(); + +/** + * @brief Evaluates if the user input is valid and allowed. + * + * Sets the members from the ManualMovesGlobals global variable to their respective values (block id and locations). + * @param GtkWidget* widget: Needed for gtk functions. + * @param GtkWidget* grid: Needed to extract members from the manual move window. + */ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); + +/** + * @brief In -detail checking of the user's input. + * + * Checks if the user input is between the grid's dimensions, block comptaibility, if the block requested to move is valid, if the block is fixed, and if the curent location of the block is different from the location requested by the user. + * @param block_id: The ID of the block to move. + * @param to: Location of where the user wants to move the block. + * + * @return True if all conditions are met, false otherwise. + */ bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to); -void get_manual_move_flag(); + +/** + * @brief Draws the cost summary dialog. + * + * Window displays the delta cost, delta timing, delta bounding box timing, annealing decision to the user. Waits for the user to ACCEPT/REJECT the manual move. + */ void cost_summary_dialog(); + +/** + * @brief Highlights new block location + * + * Highlights block in the new location if the manual move flag is active and the user accepted the manual move. + * @param manual_move_flag: Needed to check the state of the manual move toggle button. + */ void highlight_new_block_location(bool manual_move_flag); +/** + * @brief Disables the mm_window_is_open boolean and destroys the window + */ +void close_manual_moves_window(); + #endif /*NO_GRAPHICS*/ -ManualMovesGlobals* get_manual_moves_global(); +/** + * @brief Updates the ManualMovesGlobals global veriable members. + * + * @param d_cost: Delta cost for cost summary dialog function. + * @param d_timing: Delta timing for cost summary dialog function. + * @param d_bounding_box: Delta bounding box for cost summary dialog function. + * @param move_outcome: Move result from placement for cost summary dialog function. + */ void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); + +/** + * @brief Checks if the given string is a number + * + * @return True if the string only contains numbers, false otherwise. + */ bool string_is_a_number(std::string block_id); #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 103f87b7d24..f63693fd22b 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -1,3 +1,10 @@ +/* + * @file manual_move_generator.cpp + * @author Paula Perdomo + * @date 2021-07-19 + * @brief Contains the ManualMoveGenerator class memeber definitions. + */ + #include "manual_move_generator.h" #include "manual_moves.h" diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index aebce85e4ec..1b8aaa5f93e 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -1,3 +1,10 @@ +/* + * @file manual_move_generator.h + * @author Paula Perdomo + * @date 2021-07-19 + * @brief Contains the ManualMoveGenerator class. + */ + #ifndef VPR_MANUAL_MOVE_GEN_H #define VPR_MANUAL_MOVE_GEN_H @@ -12,14 +19,18 @@ #include "simpleRL_move_generator.h" #include -/** Manual Moves Generator, inherits from MoveGenerator class **/ +/** + * @brief Manual Moves Generator, inherits from MoveGenerator class. + * + * Manual Move Generator, needed for swapping blocks requested by the user. +*/ class ManualMoveGenerator : public MoveGenerator { private: std::vector> avail_moves; // list of pointers to the available move generators (the different move types) std::unique_ptr karmed_bandit_agent; // a pointer to the specific agent used (e.g. Softmax) public: - // constructors using a pointer to the agent used + //Constructors using a pointer to the agent used ManualMoveGenerator(std::unique_ptr& agent); ManualMoveGenerator(std::unique_ptr& agent); diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index b903dabde97..4b1e1a87d14 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1325,6 +1325,7 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; + //When manual move toggle button is active, the manual move window asks the user for input. ManualMovesGlobals* manual_move_global = get_manual_moves_global(); if (manual_move_global->manual_move_flag) { #ifndef NO_GRAPHICS @@ -1422,6 +1423,7 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); + //Updates the manaul_move_global members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); #ifndef NO_GRAPHICS From 1adeccd980930f38dc85335381bb7c9908052bf6 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 19 Jul 2021 20:14:29 -0400 Subject: [PATCH 30/46] Moved the manual moves global variable to draw state struct --- vpr/src/draw/draw.cpp | 8 +-- vpr/src/draw/draw_types.cpp | 2 +- vpr/src/draw/draw_types.h | 2 + vpr/src/draw/manual_moves.cpp | 96 +++++++++++++------------ vpr/src/draw/manual_moves.h | 33 ++++----- vpr/src/place/manual_move_generator.cpp | 15 +++- vpr/src/place/manual_move_generator.h | 2 +- vpr/src/place/place.cpp | 18 ++--- 8 files changed, 94 insertions(+), 82 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 5adc801b60c..7f0a18ccc58 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -4298,6 +4298,7 @@ static void draw_placement_macros(ezgl::renderer* g) { static void highlight_blocks(double x, double y) { t_draw_coords* draw_coords = get_draw_coords_vars(); + t_draw_state* draw_state = get_draw_state_vars(); char msg[vtr::bufsize]; ClusterBlockId clb_index = EMPTY_BLOCK_ID; @@ -4370,10 +4371,9 @@ static void highlight_blocks(double x, double y) { } //If manual moves is activated, then user can select block from the grid. - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - if (manual_move_global->manual_move_flag) { - manual_move_global->user_highlighted_block = true; - if (!manual_move_global->mm_window_is_open) { + if (draw_state->manual_moves_global.manual_move_flag) { + draw_state->manual_moves_global.user_highlighted_block = true; + if (!draw_state->manual_moves_global.mm_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } diff --git a/vpr/src/draw/draw_types.cpp b/vpr/src/draw/draw_types.cpp index e2ce430e8bb..c180d00f52f 100644 --- a/vpr/src/draw/draw_types.cpp +++ b/vpr/src/draw/draw_types.cpp @@ -1,7 +1,7 @@ #ifndef NO_GRAPHICS -# include "draw_global.h" # include "draw_types.h" +# include "draw_global.h" # include "globals.h" # include "vpr_utils.h" # include "draw.h" diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index b6e011c855d..0c344396220 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -27,6 +27,7 @@ # include "vtr_color_map.h" # include "vtr_vector.h" # include "breakpoint.h" +# include "manual_moves.h" # include "ezgl/point.hpp" # include "ezgl/rectangle.hpp" @@ -196,6 +197,7 @@ struct t_draw_state { int sequence_number = 0; float net_alpha = 0.1; float pres_fac = 1.; + ManualMovesGlobals manual_moves_global; std::vector list_of_breakpoints; diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 1c67eef4d4c..97375747081 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -8,32 +8,30 @@ */ #include "manual_moves.h" -#include "move_utils.h" #include "globals.h" #include "draw.h" #include "buttons.h" -//Global Variables -ManualMovesGlobals manual_moves_global; - #ifndef NO_GRAPHICS void draw_manual_moves_window(std::string block_id) { - if (!manual_moves_global.mm_window_is_open) { - manual_moves_global.mm_window_is_open = true; + t_draw_state* draw_state = get_draw_state_vars(); + + if (!draw_state->manual_moves_global.mm_window_is_open) { + draw_state->manual_moves_global.mm_window_is_open = true; //Window settings- - manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position((GtkWindow*)manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); - gtk_window_set_title((GtkWindow*)manual_moves_global.manual_move_window, "Manual Moves Generator"); - gtk_widget_set_name(manual_moves_global.manual_move_window, "manual_move_window"); + draw_state->manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position((GtkWindow*)draw_state->manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*)draw_state->manual_moves_global.manual_move_window, "Manual Moves Generator"); + gtk_widget_set_name(draw_state->manual_moves_global.manual_move_window, "manual_move_window"); GtkWidget* grid = gtk_grid_new(); GtkWidget* block_entry = gtk_entry_new(); - if (manual_moves_global.user_highlighted_block) { + if (draw_state->manual_moves_global.user_highlighted_block) { gtk_entry_set_text((GtkEntry*)block_entry, block_id.c_str()); - manual_moves_global.user_highlighted_block = false; + draw_state->manual_moves_global.user_highlighted_block = false; } GtkWidget* x_position_entry = gtk_entry_new(); @@ -73,14 +71,16 @@ void draw_manual_moves_window(std::string block_id) { //connect signals g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); - g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + g_signal_connect(G_OBJECT(draw_state->manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); - gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); - gtk_widget_show_all(manual_moves_global.manual_move_window); + gtk_container_add(GTK_CONTAINER(draw_state->manual_moves_global.manual_move_window), grid); + gtk_widget_show_all(draw_state->manual_moves_global.manual_move_window); } } void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { + t_draw_state* draw_state = get_draw_state_vars(); + int block_id; int x_location; int y_location; @@ -117,16 +117,16 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { valid_input = checking_legality_conditions(ClusterBlockId(block_id), to); if (valid_input) { - manual_moves_global.manual_move_info.valid_input = true; - manual_moves_global.manual_move_info.blockID = block_id; - manual_moves_global.manual_move_info.x_pos = x_location; - manual_moves_global.manual_move_info.y_pos = y_location; - manual_moves_global.manual_move_info.subtile = subtile_location; - manual_moves_global.manual_move_info.to_location = to; + draw_state->manual_moves_global.manual_move_info.valid_input = true; + draw_state->manual_moves_global.manual_move_info.blockID = block_id; + draw_state->manual_moves_global.manual_move_info.x_pos = x_location; + draw_state->manual_moves_global.manual_move_info.y_pos = y_location; + draw_state->manual_moves_global.manual_move_info.subtile = subtile_location; + draw_state->manual_moves_global.manual_move_info.to_location = to; //Highlighting the block deselect_all(); - ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); application.refresh_drawing(); @@ -135,7 +135,7 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { ezgl::press_proceed(proceed, &application); } else { - manual_moves_global.manual_move_info.valid_input = false; + draw_state->manual_moves_global.manual_move_info.valid_input = false; } } @@ -185,18 +185,21 @@ bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { } void get_manual_move_flag() { + t_draw_state* draw_state = get_draw_state_vars(); GObject* manual_moves = application.get_object("manualMove"); //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); - manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); + draw_state->manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); } void cost_summary_dialog() { + t_draw_state* draw_state = get_draw_state_vars(); + GtkWidget* dialog; GtkWidget* content_area; //Creating the dialog window dialog = gtk_dialog_new_with_buttons("Move Costs", - (GtkWindow*)manual_moves_global.manual_move_window, + (GtkWindow*)draw_state->manual_moves_global.manual_move_window, GTK_DIALOG_DESTROY_WITH_PARENT, ("Accept"), GTK_RESPONSE_ACCEPT, @@ -210,13 +213,13 @@ void cost_summary_dialog() { //Create elements for the dialog and printing costs to the user. GtkWidget* title_label = gtk_label_new(NULL); gtk_label_set_markup((GtkLabel*)title_label, "Move Costs and Outcomes"); - std::string delta_cost = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost) + " "; + std::string delta_cost = "Delta Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_cost) + " "; GtkWidget* delta_cost_label = gtk_label_new(delta_cost.c_str()); - std::string delta_timing = " Delta Timing: " + std::to_string(manual_moves_global.manual_move_info.delta_timing) + " "; + std::string delta_timing = " Delta Timing: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_timing) + " "; GtkWidget* delta_timing_label = gtk_label_new(delta_timing.c_str()); - std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box) + " "; + std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_bounding_box) + " "; GtkWidget* delta_bounding_box_label = gtk_label_new(delta_bounding_box.c_str()); - std::string outcome = e_move_result_to_string(manual_moves_global.manual_move_info.placer_move_outcome); + std::string outcome = e_move_result_to_string(draw_state->manual_moves_global.manual_move_info.placer_move_outcome); std::string move_outcome = " Annealing Decision: " + outcome + " "; GtkWidget* move_outcome_label = gtk_label_new(move_outcome.c_str()); GtkWidget* space_label1 = gtk_label_new(" "); @@ -236,24 +239,24 @@ void cost_summary_dialog() { gtk_widget_show_all(dialog); //Update message if user accepts the move. - std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); - msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; + std::string msg = "Manual move accepted. Block #" + std::to_string(draw_state->manual_moves_global.manual_move_info.blockID); + msg += " to location (" + std::to_string(draw_state->manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(draw_state->manual_moves_global.manual_move_info.y_pos) + ")"; //Waiting for the user to respond to return to try_swa function. int result = gtk_dialog_run(GTK_DIALOG(dialog)); switch (result) { //If the user accepts the manual move case GTK_RESPONSE_ACCEPT: - manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + draw_state->manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; application.update_message(msg.c_str()); break; //If the user rejects the manual move case GTK_RESPONSE_REJECT: - manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + draw_state->manual_moves_global.manual_move_info.user_move_outcome = REJECTED; application.update_message("Manual move was rejected"); break; default: - manual_moves_global.manual_move_info.user_move_outcome = ABORTED; + draw_state->manual_moves_global.manual_move_info.user_move_outcome = ABORTED; break; } @@ -262,12 +265,14 @@ void cost_summary_dialog() { } void highlight_new_block_location(bool manual_move_flag) { + t_draw_state* draw_state = get_draw_state_vars(); + if (manual_move_flag) { auto& cluster_ctx = g_vpr_ctx.clustering(); //Unselects all blocks first deselect_all(); //Highlighting the block - ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); application.refresh_drawing(); } @@ -275,23 +280,22 @@ void highlight_new_block_location(bool manual_move_flag) { //Manual move window turns false, the window is destroyed. void close_manual_moves_window() { - manual_moves_global.mm_window_is_open = false; + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->manual_moves_global.mm_window_is_open = false; } -#endif /*NO_GRAPHICS*/ - -/**NO_GRAPHICS FUNCTIONS**/ - ManualMovesGlobals* get_manual_moves_global() { - return &manual_moves_global; + t_draw_state* draw_state = get_draw_state_vars(); + return &draw_state->manual_moves_global; } //Updates ManualMovesInfo cost members void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { - manual_moves_global.manual_move_info.delta_cost = d_cost; - manual_moves_global.manual_move_info.delta_timing = d_timing; - manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; - manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->manual_moves_global.manual_move_info.delta_cost = d_cost; + draw_state->manual_moves_global.manual_move_info.delta_timing = d_timing; + draw_state->manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; + draw_state->manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; } bool string_is_a_number(std::string block_id) { @@ -303,3 +307,5 @@ bool string_is_a_number(std::string block_id) { } return true; } + +#endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index b5b9a668ac4..10991ba2cbf 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -13,20 +13,15 @@ /** This file contains all functions for manual moves **/ #ifndef NO_GRAPHICS -# include "draw_global.h" -# include "draw_global.h" # include "ezgl/application.hpp" # include "ezgl/graphics.hpp" - -#endif /*NO_GRAPHICS*/ - -#include "move_utils.h" -#include -#include -#include -#include -#include -#include +# include "move_utils.h" +# include +# include +# include +# include +# include +# include /** * @brief ManualMovesInfo struct @@ -59,16 +54,11 @@ struct ManualMovesGlobals { bool mm_window_is_open = false; bool user_highlighted_block = false; bool manual_move_flag = false; -#ifndef NO_GRAPHICS GtkWidget* manual_move_window; -#endif /*NO_GRAPHICS*/ }; -#ifndef NO_GRAPHICS - /** manual moves functions **/ - /** * @brief Gets the state of the manual moves togle button and assigns it to the manual_move_flag in the ManualMovesGlobal struct. */ @@ -129,8 +119,6 @@ void highlight_new_block_location(bool manual_move_flag); */ void close_manual_moves_window(); -#endif /*NO_GRAPHICS*/ - /** * @brief Updates the ManualMovesGlobals global veriable members. * @@ -148,4 +136,11 @@ void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_ */ bool string_is_a_number(std::string block_id); +/** + * @brief Used to assign the to location and block location in differen files. + */ +void get_manual_moves_globals_block_and_location(int block_id, t_pl_loc to); + +#endif /*NO_GRAPHICS*/ + #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index f63693fd22b..e108439ff7e 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -8,6 +8,13 @@ #include "manual_move_generator.h" #include "manual_moves.h" +#ifndef NO_GRAPHICS + +# include "draw_types.h" +# include "draw_global.h" + +#endif /*NO_GRAPHICS*/ + ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { avail_moves.push_back(std::move(std::make_unique())); avail_moves.push_back(std::move(std::make_unique())); @@ -33,10 +40,11 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag } //Manual Move Generator function +#ifndef NO_GRAPHICS e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - int block_id = manual_move_global->manual_move_info.blockID; - t_pl_loc to = manual_move_global->manual_move_info.to_location; + t_draw_state* draw_state = get_draw_state_vars(); + int block_id = draw_state->manual_moves_global.manual_move_info.blockID; + t_pl_loc to = draw_state->manual_moves_global.manual_move_info.to_location; ClusterBlockId b_from = ClusterBlockId(block_id); //Checking if the block was found @@ -68,3 +76,4 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; } +#endif /*NO_GRAPHICS*/ diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index 1b8aaa5f93e..8cc2cdf100d 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -23,7 +23,7 @@ * @brief Manual Moves Generator, inherits from MoveGenerator class. * * Manual Move Generator, needed for swapping blocks requested by the user. -*/ + */ class ManualMoveGenerator : public MoveGenerator { private: std::vector> avail_moves; // list of pointers to the available move generators (the different move types) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 4b1e1a87d14..f94a785bde5 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1326,14 +1326,14 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; //When manual move toggle button is active, the manual move window asks the user for input. - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - if (manual_move_global->manual_move_flag) { #ifndef NO_GRAPHICS + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->manual_moves_global.manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); #endif /*NO_GRAPHICS*/ - create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); @@ -1423,15 +1423,15 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); +#ifndef NO_GRAPHICS //Updates the manaul_move_global members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. - if (manual_move_global->manual_move_flag) { + if (draw_state->manual_moves_global.manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); -#ifndef NO_GRAPHICS cost_summary_dialog(); -#endif /*NO_GRAPHICS*/ //User accepts or rejects the move. - move_outcome = manual_move_global->manual_move_info.user_move_outcome; + move_outcome = draw_state->manual_moves_global.manual_move_info.user_move_outcome; } +#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; @@ -1470,8 +1470,8 @@ static e_move_result try_swap(const t_annealing_state* state, //Highlights the new block when manual move is selected. #ifndef NO_GRAPHICS - highlight_new_block_location(manual_move_global->manual_move_flag); -#endif /*NO_GRPAHICS*/ + highlight_new_block_location(draw_state->manual_moves_global.manual_move_flag); +#endif /*NO_GRAPHICS*/ } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); From 03a1d14e55fad495d2c2505bebdb8fcbad74db9e Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 19 Jul 2021 20:49:09 -0400 Subject: [PATCH 31/46] Testing our graphics compilation guards --- vpr/src/place/place.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index f94a785bde5..1c57ecf5d99 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1326,12 +1326,11 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; //When manual move toggle button is active, the manual move window asks the user for input. -#ifndef NO_GRAPHICS t_draw_state* draw_state = get_draw_state_vars(); if (draw_state->manual_moves_global.manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); -#endif /*NO_GRAPHICS*/ + create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } else { From 2892dc4263dea79544b8fbf7c952bd988fc77404 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 19 Jul 2021 21:20:23 -0400 Subject: [PATCH 32/46] Moving the NO_GRAPHICS guards in place.cpp --- vpr/src/place/place.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 1c57ecf5d99..dce68151cdd 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1325,6 +1325,7 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; +#ifndef NO_GRAPHICS //When manual move toggle button is active, the manual move window asks the user for input. t_draw_state* draw_state = get_draw_state_vars(); if (draw_state->manual_moves_global.manual_move_flag) { @@ -1337,6 +1338,7 @@ static e_move_result try_swap(const t_annealing_state* state, //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } +#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); From 94808cbc2d03303b35b3fdfdaa80114e87759a38 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 19 Jul 2021 23:06:40 -0400 Subject: [PATCH 33/46] Moved the graphics guard in manual_move_generator.cpp --- vpr/src/place/manual_move_generator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index e108439ff7e..362595a47fb 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -40,8 +40,8 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag } //Manual Move Generator function -#ifndef NO_GRAPHICS e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { +#ifndef NO_GRAPHICS t_draw_state* draw_state = get_draw_state_vars(); int block_id = draw_state->manual_moves_global.manual_move_info.blockID; t_pl_loc to = draw_state->manual_moves_global.manual_move_info.to_location; @@ -75,5 +75,5 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; -} #endif /*NO_GRAPHICS*/ +} From 1284d5db4b7809dd4fa7f5e4d102a9cc4cee7161 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 19 Jul 2021 23:34:36 -0400 Subject: [PATCH 34/46] Reverting to commit 8fcac3554 --- vpr/src/draw/draw.cpp | 8 +-- vpr/src/draw/draw_types.cpp | 2 +- vpr/src/draw/draw_types.h | 2 - vpr/src/draw/manual_moves.cpp | 96 ++++++++++++------------- vpr/src/draw/manual_moves.h | 33 +++++---- vpr/src/place/manual_move_generator.cpp | 15 +--- vpr/src/place/manual_move_generator.h | 2 +- vpr/src/place/place.cpp | 21 +++--- 8 files changed, 83 insertions(+), 96 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 7f0a18ccc58..5adc801b60c 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -4298,7 +4298,6 @@ static void draw_placement_macros(ezgl::renderer* g) { static void highlight_blocks(double x, double y) { t_draw_coords* draw_coords = get_draw_coords_vars(); - t_draw_state* draw_state = get_draw_state_vars(); char msg[vtr::bufsize]; ClusterBlockId clb_index = EMPTY_BLOCK_ID; @@ -4371,9 +4370,10 @@ static void highlight_blocks(double x, double y) { } //If manual moves is activated, then user can select block from the grid. - if (draw_state->manual_moves_global.manual_move_flag) { - draw_state->manual_moves_global.user_highlighted_block = true; - if (!draw_state->manual_moves_global.mm_window_is_open) { + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + if (manual_move_global->manual_move_flag) { + manual_move_global->user_highlighted_block = true; + if (!manual_move_global->mm_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } diff --git a/vpr/src/draw/draw_types.cpp b/vpr/src/draw/draw_types.cpp index c180d00f52f..e2ce430e8bb 100644 --- a/vpr/src/draw/draw_types.cpp +++ b/vpr/src/draw/draw_types.cpp @@ -1,7 +1,7 @@ #ifndef NO_GRAPHICS -# include "draw_types.h" # include "draw_global.h" +# include "draw_types.h" # include "globals.h" # include "vpr_utils.h" # include "draw.h" diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index 0c344396220..b6e011c855d 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -27,7 +27,6 @@ # include "vtr_color_map.h" # include "vtr_vector.h" # include "breakpoint.h" -# include "manual_moves.h" # include "ezgl/point.hpp" # include "ezgl/rectangle.hpp" @@ -197,7 +196,6 @@ struct t_draw_state { int sequence_number = 0; float net_alpha = 0.1; float pres_fac = 1.; - ManualMovesGlobals manual_moves_global; std::vector list_of_breakpoints; diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 97375747081..1c67eef4d4c 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -8,30 +8,32 @@ */ #include "manual_moves.h" +#include "move_utils.h" #include "globals.h" #include "draw.h" #include "buttons.h" +//Global Variables +ManualMovesGlobals manual_moves_global; + #ifndef NO_GRAPHICS void draw_manual_moves_window(std::string block_id) { - t_draw_state* draw_state = get_draw_state_vars(); - - if (!draw_state->manual_moves_global.mm_window_is_open) { - draw_state->manual_moves_global.mm_window_is_open = true; + if (!manual_moves_global.mm_window_is_open) { + manual_moves_global.mm_window_is_open = true; //Window settings- - draw_state->manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position((GtkWindow*)draw_state->manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); - gtk_window_set_title((GtkWindow*)draw_state->manual_moves_global.manual_move_window, "Manual Moves Generator"); - gtk_widget_set_name(draw_state->manual_moves_global.manual_move_window, "manual_move_window"); + manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position((GtkWindow*)manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*)manual_moves_global.manual_move_window, "Manual Moves Generator"); + gtk_widget_set_name(manual_moves_global.manual_move_window, "manual_move_window"); GtkWidget* grid = gtk_grid_new(); GtkWidget* block_entry = gtk_entry_new(); - if (draw_state->manual_moves_global.user_highlighted_block) { + if (manual_moves_global.user_highlighted_block) { gtk_entry_set_text((GtkEntry*)block_entry, block_id.c_str()); - draw_state->manual_moves_global.user_highlighted_block = false; + manual_moves_global.user_highlighted_block = false; } GtkWidget* x_position_entry = gtk_entry_new(); @@ -71,16 +73,14 @@ void draw_manual_moves_window(std::string block_id) { //connect signals g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); - g_signal_connect(G_OBJECT(draw_state->manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); - gtk_container_add(GTK_CONTAINER(draw_state->manual_moves_global.manual_move_window), grid); - gtk_widget_show_all(draw_state->manual_moves_global.manual_move_window); + gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); + gtk_widget_show_all(manual_moves_global.manual_move_window); } } void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { - t_draw_state* draw_state = get_draw_state_vars(); - int block_id; int x_location; int y_location; @@ -117,16 +117,16 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { valid_input = checking_legality_conditions(ClusterBlockId(block_id), to); if (valid_input) { - draw_state->manual_moves_global.manual_move_info.valid_input = true; - draw_state->manual_moves_global.manual_move_info.blockID = block_id; - draw_state->manual_moves_global.manual_move_info.x_pos = x_location; - draw_state->manual_moves_global.manual_move_info.y_pos = y_location; - draw_state->manual_moves_global.manual_move_info.subtile = subtile_location; - draw_state->manual_moves_global.manual_move_info.to_location = to; + manual_moves_global.manual_move_info.valid_input = true; + manual_moves_global.manual_move_info.blockID = block_id; + manual_moves_global.manual_move_info.x_pos = x_location; + manual_moves_global.manual_move_info.y_pos = y_location; + manual_moves_global.manual_move_info.subtile = subtile_location; + manual_moves_global.manual_move_info.to_location = to; //Highlighting the block deselect_all(); - ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); + ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); application.refresh_drawing(); @@ -135,7 +135,7 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { ezgl::press_proceed(proceed, &application); } else { - draw_state->manual_moves_global.manual_move_info.valid_input = false; + manual_moves_global.manual_move_info.valid_input = false; } } @@ -185,21 +185,18 @@ bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { } void get_manual_move_flag() { - t_draw_state* draw_state = get_draw_state_vars(); GObject* manual_moves = application.get_object("manualMove"); //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); - draw_state->manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); + manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); } void cost_summary_dialog() { - t_draw_state* draw_state = get_draw_state_vars(); - GtkWidget* dialog; GtkWidget* content_area; //Creating the dialog window dialog = gtk_dialog_new_with_buttons("Move Costs", - (GtkWindow*)draw_state->manual_moves_global.manual_move_window, + (GtkWindow*)manual_moves_global.manual_move_window, GTK_DIALOG_DESTROY_WITH_PARENT, ("Accept"), GTK_RESPONSE_ACCEPT, @@ -213,13 +210,13 @@ void cost_summary_dialog() { //Create elements for the dialog and printing costs to the user. GtkWidget* title_label = gtk_label_new(NULL); gtk_label_set_markup((GtkLabel*)title_label, "Move Costs and Outcomes"); - std::string delta_cost = "Delta Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_cost) + " "; + std::string delta_cost = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost) + " "; GtkWidget* delta_cost_label = gtk_label_new(delta_cost.c_str()); - std::string delta_timing = " Delta Timing: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_timing) + " "; + std::string delta_timing = " Delta Timing: " + std::to_string(manual_moves_global.manual_move_info.delta_timing) + " "; GtkWidget* delta_timing_label = gtk_label_new(delta_timing.c_str()); - std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_bounding_box) + " "; + std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box) + " "; GtkWidget* delta_bounding_box_label = gtk_label_new(delta_bounding_box.c_str()); - std::string outcome = e_move_result_to_string(draw_state->manual_moves_global.manual_move_info.placer_move_outcome); + std::string outcome = e_move_result_to_string(manual_moves_global.manual_move_info.placer_move_outcome); std::string move_outcome = " Annealing Decision: " + outcome + " "; GtkWidget* move_outcome_label = gtk_label_new(move_outcome.c_str()); GtkWidget* space_label1 = gtk_label_new(" "); @@ -239,24 +236,24 @@ void cost_summary_dialog() { gtk_widget_show_all(dialog); //Update message if user accepts the move. - std::string msg = "Manual move accepted. Block #" + std::to_string(draw_state->manual_moves_global.manual_move_info.blockID); - msg += " to location (" + std::to_string(draw_state->manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(draw_state->manual_moves_global.manual_move_info.y_pos) + ")"; + std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); + msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; //Waiting for the user to respond to return to try_swa function. int result = gtk_dialog_run(GTK_DIALOG(dialog)); switch (result) { //If the user accepts the manual move case GTK_RESPONSE_ACCEPT: - draw_state->manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; application.update_message(msg.c_str()); break; //If the user rejects the manual move case GTK_RESPONSE_REJECT: - draw_state->manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + manual_moves_global.manual_move_info.user_move_outcome = REJECTED; application.update_message("Manual move was rejected"); break; default: - draw_state->manual_moves_global.manual_move_info.user_move_outcome = ABORTED; + manual_moves_global.manual_move_info.user_move_outcome = ABORTED; break; } @@ -265,14 +262,12 @@ void cost_summary_dialog() { } void highlight_new_block_location(bool manual_move_flag) { - t_draw_state* draw_state = get_draw_state_vars(); - if (manual_move_flag) { auto& cluster_ctx = g_vpr_ctx.clustering(); //Unselects all blocks first deselect_all(); //Highlighting the block - ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); + ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); application.refresh_drawing(); } @@ -280,22 +275,23 @@ void highlight_new_block_location(bool manual_move_flag) { //Manual move window turns false, the window is destroyed. void close_manual_moves_window() { - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->manual_moves_global.mm_window_is_open = false; + manual_moves_global.mm_window_is_open = false; } +#endif /*NO_GRAPHICS*/ + +/**NO_GRAPHICS FUNCTIONS**/ + ManualMovesGlobals* get_manual_moves_global() { - t_draw_state* draw_state = get_draw_state_vars(); - return &draw_state->manual_moves_global; + return &manual_moves_global; } //Updates ManualMovesInfo cost members void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->manual_moves_global.manual_move_info.delta_cost = d_cost; - draw_state->manual_moves_global.manual_move_info.delta_timing = d_timing; - draw_state->manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; - draw_state->manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; + manual_moves_global.manual_move_info.delta_cost = d_cost; + manual_moves_global.manual_move_info.delta_timing = d_timing; + manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; + manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; } bool string_is_a_number(std::string block_id) { @@ -307,5 +303,3 @@ bool string_is_a_number(std::string block_id) { } return true; } - -#endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 10991ba2cbf..b5b9a668ac4 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -13,15 +13,20 @@ /** This file contains all functions for manual moves **/ #ifndef NO_GRAPHICS +# include "draw_global.h" +# include "draw_global.h" # include "ezgl/application.hpp" # include "ezgl/graphics.hpp" -# include "move_utils.h" -# include -# include -# include -# include -# include -# include + +#endif /*NO_GRAPHICS*/ + +#include "move_utils.h" +#include +#include +#include +#include +#include +#include /** * @brief ManualMovesInfo struct @@ -54,11 +59,16 @@ struct ManualMovesGlobals { bool mm_window_is_open = false; bool user_highlighted_block = false; bool manual_move_flag = false; +#ifndef NO_GRAPHICS GtkWidget* manual_move_window; +#endif /*NO_GRAPHICS*/ }; +#ifndef NO_GRAPHICS + /** manual moves functions **/ + /** * @brief Gets the state of the manual moves togle button and assigns it to the manual_move_flag in the ManualMovesGlobal struct. */ @@ -119,6 +129,8 @@ void highlight_new_block_location(bool manual_move_flag); */ void close_manual_moves_window(); +#endif /*NO_GRAPHICS*/ + /** * @brief Updates the ManualMovesGlobals global veriable members. * @@ -136,11 +148,4 @@ void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_ */ bool string_is_a_number(std::string block_id); -/** - * @brief Used to assign the to location and block location in differen files. - */ -void get_manual_moves_globals_block_and_location(int block_id, t_pl_loc to); - -#endif /*NO_GRAPHICS*/ - #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 362595a47fb..f63693fd22b 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -8,13 +8,6 @@ #include "manual_move_generator.h" #include "manual_moves.h" -#ifndef NO_GRAPHICS - -# include "draw_types.h" -# include "draw_global.h" - -#endif /*NO_GRAPHICS*/ - ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { avail_moves.push_back(std::move(std::make_unique())); avail_moves.push_back(std::move(std::make_unique())); @@ -41,10 +34,9 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag //Manual Move Generator function e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { -#ifndef NO_GRAPHICS - t_draw_state* draw_state = get_draw_state_vars(); - int block_id = draw_state->manual_moves_global.manual_move_info.blockID; - t_pl_loc to = draw_state->manual_moves_global.manual_move_info.to_location; + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + int block_id = manual_move_global->manual_move_info.blockID; + t_pl_loc to = manual_move_global->manual_move_info.to_location; ClusterBlockId b_from = ClusterBlockId(block_id); //Checking if the block was found @@ -75,5 +67,4 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; -#endif /*NO_GRAPHICS*/ } diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index 8cc2cdf100d..1b8aaa5f93e 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -23,7 +23,7 @@ * @brief Manual Moves Generator, inherits from MoveGenerator class. * * Manual Move Generator, needed for swapping blocks requested by the user. - */ +*/ class ManualMoveGenerator : public MoveGenerator { private: std::vector> avail_moves; // list of pointers to the available move generators (the different move types) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index dce68151cdd..4b1e1a87d14 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1325,20 +1325,19 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; -#ifndef NO_GRAPHICS //When manual move toggle button is active, the manual move window asks the user for input. - t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->manual_moves_global.manual_move_flag) { + ManualMovesGlobals* manual_move_global = get_manual_moves_global(); + if (manual_move_global->manual_move_flag) { +#ifndef NO_GRAPHICS draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); +#endif /*NO_GRAPHICS*/ create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); - } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } -#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1424,15 +1423,15 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); -#ifndef NO_GRAPHICS //Updates the manaul_move_global members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. - if (draw_state->manual_moves_global.manual_move_flag) { + if (manual_move_global->manual_move_flag) { update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); +#ifndef NO_GRAPHICS cost_summary_dialog(); +#endif /*NO_GRAPHICS*/ //User accepts or rejects the move. - move_outcome = draw_state->manual_moves_global.manual_move_info.user_move_outcome; + move_outcome = manual_move_global->manual_move_info.user_move_outcome; } -#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; @@ -1471,8 +1470,8 @@ static e_move_result try_swap(const t_annealing_state* state, //Highlights the new block when manual move is selected. #ifndef NO_GRAPHICS - highlight_new_block_location(draw_state->manual_moves_global.manual_move_flag); -#endif /*NO_GRAPHICS*/ + highlight_new_block_location(manual_move_global->manual_move_flag); +#endif /*NO_GRPAHICS*/ } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); From 1ea9fb27de123f627e4b379a562b7580d70a47c5 Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 20 Jul 2021 11:23:30 -0400 Subject: [PATCH 35/46] Changed function declaration order in manual moves --- vpr/src/draw/manual_moves.h | 15 +++++++-------- vpr/src/place/manual_move_generator.cpp | 1 + vpr/src/place/manual_move_generator.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index b5b9a668ac4..8e63727e9fd 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -68,19 +68,11 @@ struct ManualMovesGlobals { /** manual moves functions **/ - /** * @brief Gets the state of the manual moves togle button and assigns it to the manual_move_flag in the ManualMovesGlobal struct. */ void get_manual_move_flag(); -/** - * @brief Gets the manual_moves_global variables in manual_move.cpp. - * - * @return The manual_moves_global variable. - */ -ManualMovesGlobals* get_manual_moves_global(); - /** * @brief Draws the manual move window. * @@ -131,6 +123,13 @@ void close_manual_moves_window(); #endif /*NO_GRAPHICS*/ +/** + * @brief Gets the manual_moves_global variables in manual_move.cpp. + * + * @return The manual_moves_global variable. + */ +ManualMovesGlobals* get_manual_moves_global(); + /** * @brief Updates the ManualMovesGlobals global veriable members. * diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index f63693fd22b..cca6a228f23 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -37,6 +37,7 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ ManualMovesGlobals* manual_move_global = get_manual_moves_global(); int block_id = manual_move_global->manual_move_info.blockID; t_pl_loc to = manual_move_global->manual_move_info.to_location; + ClusterBlockId b_from = ClusterBlockId(block_id); //Checking if the block was found diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index 1b8aaa5f93e..8cc2cdf100d 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -23,7 +23,7 @@ * @brief Manual Moves Generator, inherits from MoveGenerator class. * * Manual Move Generator, needed for swapping blocks requested by the user. -*/ + */ class ManualMoveGenerator : public MoveGenerator { private: std::vector> avail_moves; // list of pointers to the available move generators (the different move types) From d27116f50f055cb1af76be131b6dda3c05d5e739 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 21 Jul 2021 11:08:08 -0400 Subject: [PATCH 36/46] Fixed gtk warnings when --disp off --- vpr/src/place/manual_move_generator.cpp | 21 ++++++----- vpr/src/place/place.cpp | 50 ++++++++++++++++--------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index cca6a228f23..c73597acd5c 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -55,16 +55,17 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ auto grid_from_type = device_ctx.grid[from.x][from.y].type; VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); - //Retrieving the compressed block grid for this block type - const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; - //Checking if the block has a compatible subtile. - auto to_type = device_ctx.grid[to.x][to.y].type; - auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); - - //No compatible subtile is found. - if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { - return e_create_move::ABORT; - } + /* + * //Retrieving the compressed block grid for this block type + * const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; + * //Checking if the block has a compatible subtile. + * auto to_type = device_ctx.grid[to.x][to.y].type; + * auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); + * + * //No compatible subtile is found. + * if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { + * return e_create_move::ABORT; + * }*/ e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 4b1e1a87d14..8f2c4bb7eaf 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -489,8 +489,8 @@ void try_place(const t_placer_opts& placer_opts, * pow(cluster_ctx.clb_nlist.blocks().size(), 1.3333)); //create the move generator based on the chosen strategy - create_move_generators(move_generator, move_generator2, manual_move_generator, placer_opts, - move_lim); + create_move_generators(move_generator, move_generator2, + manual_move_generator, placer_opts, move_lim); width_fac = placer_opts.place_chan_width; @@ -1183,7 +1183,9 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t for (int i = 0; i < move_lim; i++) { #ifndef NO_GRAPHICS //Checks manual move flag for manual move feature - get_manual_move_flag(); + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->show_graphics) + get_manual_move_flag(); #endif /*NO_GRAPHICS*/ //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack @@ -1333,10 +1335,12 @@ static e_move_result try_swap(const t_annealing_state* state, update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); #endif /*NO_GRAPHICS*/ - create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + create_move_outcome = manual_move_generator.propose_move( + blocks_affected, move_type, rlim, placer_opts, criticalities); } else { //Generate a new move (perturbation) used to explore the space of possible placements - create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + create_move_outcome = move_generator.propose_move(blocks_affected, + move_type, rlim, placer_opts, criticalities); } ++move_type_stat.num_moves[(int)move_type]; @@ -1425,7 +1429,8 @@ static e_move_result try_swap(const t_annealing_state* state, //Updates the manaul_move_global members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. if (manual_move_global->manual_move_flag) { - update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); + update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, + move_outcome); #ifndef NO_GRAPHICS cost_summary_dialog(); #endif /*NO_GRAPHICS*/ @@ -2730,14 +2735,18 @@ static int check_block_placement_consistency() { auto& place_ctx = g_vpr_ctx.placement(); auto& device_ctx = g_vpr_ctx.device(); - vtr::vector bdone(cluster_ctx.clb_nlist.blocks().size(), 0); + vtr::vector bdone( + cluster_ctx.clb_nlist.blocks().size(), 0); /* Step through device grid and placement. Check it against blocks */ for (size_t i = 0; i < device_ctx.grid.width(); i++) for (size_t j = 0; j < device_ctx.grid.height(); j++) { - if (place_ctx.grid_blocks[i][j].usage > device_ctx.grid[i][j].type->capacity) { - VTR_LOG_ERROR("%d blocks were placed at grid location (%zu,%zu), but location capacity is %d.\n", - place_ctx.grid_blocks[i][j].usage, i, j, device_ctx.grid[i][j].type->capacity); + if (place_ctx.grid_blocks[i][j].usage + > device_ctx.grid[i][j].type->capacity) { + VTR_LOG_ERROR( + "%d blocks were placed at grid location (%zu,%zu), but location capacity is %d.\n", + place_ctx.grid_blocks[i][j].usage, i, j, + device_ctx.grid[i][j].type->capacity); error++; } int usage_check = 0; @@ -2750,24 +2759,29 @@ static int check_block_placement_consistency() { auto physical_tile = device_ctx.grid[i][j].type; if (physical_tile_type(bnum) != physical_tile) { - VTR_LOG_ERROR("Block %zu type (%s) does not match grid location (%zu,%zu) type (%s).\n", - size_t(bnum), logical_block->name, i, j, physical_tile->name); + VTR_LOG_ERROR( + "Block %zu type (%s) does not match grid location (%zu,%zu) type (%s).\n", + size_t(bnum), logical_block->name, i, j, + physical_tile->name); error++; } auto& loc = place_ctx.block_locs[bnum].loc; - if (loc.x != int(i) || loc.y != int(j) || !is_sub_tile_compatible(physical_tile, logical_block, loc.sub_tile)) { - VTR_LOG_ERROR("Block %zu's location is (%d,%d,%d) but found in grid at (%zu,%zu,%d).\n", - size_t(bnum), loc.x, loc.y, loc.sub_tile, - i, j, k); + if (loc.x != int(i) || loc.y != int(j) + || !is_sub_tile_compatible(physical_tile, logical_block, + loc.sub_tile)) { + VTR_LOG_ERROR( + "Block %zu's location is (%d,%d,%d) but found in grid at (%zu,%zu,%d).\n", + size_t(bnum), loc.x, loc.y, loc.sub_tile, i, j, k); error++; } ++usage_check; bdone[bnum]++; } if (usage_check != place_ctx.grid_blocks[i][j].usage) { - VTR_LOG_ERROR("%d block(s) were placed at location (%zu,%zu), but location contains %d block(s).\n", - place_ctx.grid_blocks[i][j].usage, i, j, usage_check); + VTR_LOG_ERROR( + "%d block(s) were placed at location (%zu,%zu), but location contains %d block(s).\n", + place_ctx.grid_blocks[i][j].usage, i, j, usage_check); error++; } } From 7a2f521eccb55844043ab7b22e59674a83c7b1d9 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 26 Jul 2021 20:26:17 -0400 Subject: [PATCH 37/46] Adding global variables from manualmoves to draw_state struct --- vpr/src/draw/draw.cpp | 8 +- vpr/src/draw/draw_types.h | 2 + vpr/src/draw/manual_moves.cpp | 108 +++++++++++++----------- vpr/src/draw/manual_moves.h | 39 ++++----- vpr/src/place/manual_move_generator.cpp | 10 ++- vpr/src/place/place.cpp | 16 ++-- 6 files changed, 101 insertions(+), 82 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index c287bd4fe70..5ad8bb46e9c 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -4374,10 +4374,10 @@ static void highlight_blocks(double x, double y) { } //If manual moves is activated, then user can select block from the grid. - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - if (manual_move_global->manual_move_flag) { - manual_move_global->user_highlighted_block = true; - if (!manual_move_global->mm_window_is_open) { + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->manual_moves_global.manual_move_flag) { + draw_state->manual_moves_global.user_highlighted_block = true; + if (!draw_state->manual_moves_global.mm_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index b6e011c855d..0c344396220 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -27,6 +27,7 @@ # include "vtr_color_map.h" # include "vtr_vector.h" # include "breakpoint.h" +# include "manual_moves.h" # include "ezgl/point.hpp" # include "ezgl/rectangle.hpp" @@ -196,6 +197,7 @@ struct t_draw_state { int sequence_number = 0; float net_alpha = 0.1; float pres_fac = 1.; + ManualMovesGlobals manual_moves_global; std::vector list_of_breakpoints; diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 1c67eef4d4c..22b27e6bebd 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -8,32 +8,30 @@ */ #include "manual_moves.h" -#include "move_utils.h" #include "globals.h" #include "draw.h" #include "buttons.h" -//Global Variables -ManualMovesGlobals manual_moves_global; - #ifndef NO_GRAPHICS void draw_manual_moves_window(std::string block_id) { - if (!manual_moves_global.mm_window_is_open) { - manual_moves_global.mm_window_is_open = true; + t_draw_state* draw_state = get_draw_state_vars(); + + if (!draw_state->manual_moves_global.mm_window_is_open) { + draw_state->manual_moves_global.mm_window_is_open = true; //Window settings- - manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position((GtkWindow*)manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); - gtk_window_set_title((GtkWindow*)manual_moves_global.manual_move_window, "Manual Moves Generator"); - gtk_widget_set_name(manual_moves_global.manual_move_window, "manual_move_window"); + draw_state->manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position((GtkWindow*)draw_state->manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*)draw_state->manual_moves_global.manual_move_window, "Manual Moves Generator"); + gtk_widget_set_name(draw_state->manual_moves_global.manual_move_window, "manual_move_window"); GtkWidget* grid = gtk_grid_new(); GtkWidget* block_entry = gtk_entry_new(); - if (manual_moves_global.user_highlighted_block) { + if (draw_state->manual_moves_global.user_highlighted_block) { gtk_entry_set_text((GtkEntry*)block_entry, block_id.c_str()); - manual_moves_global.user_highlighted_block = false; + draw_state->manual_moves_global.user_highlighted_block = false; } GtkWidget* x_position_entry = gtk_entry_new(); @@ -73,10 +71,10 @@ void draw_manual_moves_window(std::string block_id) { //connect signals g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); - g_signal_connect(G_OBJECT(manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + g_signal_connect(G_OBJECT(draw_state->manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); - gtk_container_add(GTK_CONTAINER(manual_moves_global.manual_move_window), grid); - gtk_widget_show_all(manual_moves_global.manual_move_window); + gtk_container_add(GTK_CONTAINER(draw_state->manual_moves_global.manual_move_window), grid); + gtk_widget_show_all(draw_state->manual_moves_global.manual_move_window); } } @@ -87,6 +85,8 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { int subtile_location; bool valid_input = true; + t_draw_state* draw_state = get_draw_state_vars(); + //Loading the context/data structures needed. auto& cluster_ctx = g_vpr_ctx.clustering(); @@ -117,16 +117,16 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { valid_input = checking_legality_conditions(ClusterBlockId(block_id), to); if (valid_input) { - manual_moves_global.manual_move_info.valid_input = true; - manual_moves_global.manual_move_info.blockID = block_id; - manual_moves_global.manual_move_info.x_pos = x_location; - manual_moves_global.manual_move_info.y_pos = y_location; - manual_moves_global.manual_move_info.subtile = subtile_location; - manual_moves_global.manual_move_info.to_location = to; + draw_state->manual_moves_global.manual_move_info.valid_input = true; + draw_state->manual_moves_global.manual_move_info.blockID = block_id; + draw_state->manual_moves_global.manual_move_info.x_pos = x_location; + draw_state->manual_moves_global.manual_move_info.y_pos = y_location; + draw_state->manual_moves_global.manual_move_info.subtile = subtile_location; + draw_state->manual_moves_global.manual_move_info.to_location = to; //Highlighting the block deselect_all(); - ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); application.refresh_drawing(); @@ -135,7 +135,7 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { ezgl::press_proceed(proceed, &application); } else { - manual_moves_global.manual_move_info.valid_input = false; + draw_state->manual_moves_global.manual_move_info.valid_input = false; } } @@ -185,18 +185,20 @@ bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { } void get_manual_move_flag() { + t_draw_state* draw_state = get_draw_state_vars(); GObject* manual_moves = application.get_object("manualMove"); //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); - manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); + draw_state->manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); } void cost_summary_dialog() { + t_draw_state* draw_state = get_draw_state_vars(); GtkWidget* dialog; GtkWidget* content_area; //Creating the dialog window dialog = gtk_dialog_new_with_buttons("Move Costs", - (GtkWindow*)manual_moves_global.manual_move_window, + (GtkWindow*)draw_state->manual_moves_global.manual_move_window, GTK_DIALOG_DESTROY_WITH_PARENT, ("Accept"), GTK_RESPONSE_ACCEPT, @@ -210,13 +212,13 @@ void cost_summary_dialog() { //Create elements for the dialog and printing costs to the user. GtkWidget* title_label = gtk_label_new(NULL); gtk_label_set_markup((GtkLabel*)title_label, "Move Costs and Outcomes"); - std::string delta_cost = "Delta Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_cost) + " "; + std::string delta_cost = "Delta Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_cost) + " "; GtkWidget* delta_cost_label = gtk_label_new(delta_cost.c_str()); - std::string delta_timing = " Delta Timing: " + std::to_string(manual_moves_global.manual_move_info.delta_timing) + " "; + std::string delta_timing = " Delta Timing: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_timing) + " "; GtkWidget* delta_timing_label = gtk_label_new(delta_timing.c_str()); - std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(manual_moves_global.manual_move_info.delta_bounding_box) + " "; + std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_bounding_box) + " "; GtkWidget* delta_bounding_box_label = gtk_label_new(delta_bounding_box.c_str()); - std::string outcome = e_move_result_to_string(manual_moves_global.manual_move_info.placer_move_outcome); + std::string outcome = e_move_result_to_string(draw_state->manual_moves_global.manual_move_info.placer_move_outcome); std::string move_outcome = " Annealing Decision: " + outcome + " "; GtkWidget* move_outcome_label = gtk_label_new(move_outcome.c_str()); GtkWidget* space_label1 = gtk_label_new(" "); @@ -236,24 +238,24 @@ void cost_summary_dialog() { gtk_widget_show_all(dialog); //Update message if user accepts the move. - std::string msg = "Manual move accepted. Block #" + std::to_string(manual_moves_global.manual_move_info.blockID); - msg += " to location (" + std::to_string(manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(manual_moves_global.manual_move_info.y_pos) + ")"; + std::string msg = "Manual move accepted. Block #" + std::to_string(draw_state->manual_moves_global.manual_move_info.blockID); + msg += " to location (" + std::to_string(draw_state->manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(draw_state->manual_moves_global.manual_move_info.y_pos) + ")"; //Waiting for the user to respond to return to try_swa function. int result = gtk_dialog_run(GTK_DIALOG(dialog)); switch (result) { //If the user accepts the manual move case GTK_RESPONSE_ACCEPT: - manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + draw_state->manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; application.update_message(msg.c_str()); break; //If the user rejects the manual move case GTK_RESPONSE_REJECT: - manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + draw_state->manual_moves_global.manual_move_info.user_move_outcome = REJECTED; application.update_message("Manual move was rejected"); break; default: - manual_moves_global.manual_move_info.user_move_outcome = ABORTED; + draw_state->manual_moves_global.manual_move_info.user_move_outcome = ABORTED; break; } @@ -261,13 +263,14 @@ void cost_summary_dialog() { gtk_widget_destroy(dialog); } -void highlight_new_block_location(bool manual_move_flag) { - if (manual_move_flag) { +void highlight_new_block_location() { + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->manual_moves_global.manual_move_flag) { auto& cluster_ctx = g_vpr_ctx.clustering(); //Unselects all blocks first deselect_all(); //Highlighting the block - ClusterBlockId clb_index = ClusterBlockId(manual_moves_global.manual_move_info.blockID); + ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); application.refresh_drawing(); } @@ -275,23 +278,22 @@ void highlight_new_block_location(bool manual_move_flag) { //Manual move window turns false, the window is destroyed. void close_manual_moves_window() { - manual_moves_global.mm_window_is_open = false; + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->manual_moves_global.mm_window_is_open = false; } -#endif /*NO_GRAPHICS*/ - -/**NO_GRAPHICS FUNCTIONS**/ - ManualMovesGlobals* get_manual_moves_global() { - return &manual_moves_global; + t_draw_state* draw_state = get_draw_state_vars(); + return &draw_state->manual_moves_global; } //Updates ManualMovesInfo cost members void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { - manual_moves_global.manual_move_info.delta_cost = d_cost; - manual_moves_global.manual_move_info.delta_timing = d_timing; - manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; - manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; + t_draw_state* draw_state = get_draw_state_vars(); + draw_state->manual_moves_global.manual_move_info.delta_cost = d_cost; + draw_state->manual_moves_global.manual_move_info.delta_timing = d_timing; + draw_state->manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; + draw_state->manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; } bool string_is_a_number(std::string block_id) { @@ -303,3 +305,15 @@ bool string_is_a_number(std::string block_id) { } return true; } + +int return_block_id() { + t_draw_state* draw_state = get_draw_state_vars(); + return draw_state->manual_moves_global.manual_move_info.blockID; +} + +t_pl_loc return_to_loc() { + t_draw_state* draw_state = get_draw_state_vars(); + return draw_state->manual_moves_global.manual_move_info.to_location; +} + +#endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 8e63727e9fd..a628125a475 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -13,20 +13,16 @@ /** This file contains all functions for manual moves **/ #ifndef NO_GRAPHICS -# include "draw_global.h" -# include "draw_global.h" # include "ezgl/application.hpp" # include "ezgl/graphics.hpp" -#endif /*NO_GRAPHICS*/ - -#include "move_utils.h" -#include -#include -#include -#include -#include -#include +# include "move_utils.h" +# include +# include +# include +# include +# include +# include /** * @brief ManualMovesInfo struct @@ -59,13 +55,9 @@ struct ManualMovesGlobals { bool mm_window_is_open = false; bool user_highlighted_block = false; bool manual_move_flag = false; -#ifndef NO_GRAPHICS GtkWidget* manual_move_window; -#endif /*NO_GRAPHICS*/ }; -#ifndef NO_GRAPHICS - /** manual moves functions **/ /** @@ -112,17 +104,14 @@ void cost_summary_dialog(); * @brief Highlights new block location * * Highlights block in the new location if the manual move flag is active and the user accepted the manual move. - * @param manual_move_flag: Needed to check the state of the manual move toggle button. */ -void highlight_new_block_location(bool manual_move_flag); +void highlight_new_block_location(); /** * @brief Disables the mm_window_is_open boolean and destroys the window */ void close_manual_moves_window(); -#endif /*NO_GRAPHICS*/ - /** * @brief Gets the manual_moves_global variables in manual_move.cpp. * @@ -147,4 +136,16 @@ void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_ */ bool string_is_a_number(std::string block_id); +/** + * @brief Returns the block requested by the user for manual moves. + */ +int return_block_id(); + +/** + * @brief Returns the to location requested by the user for manual moves. + */ +t_pl_loc return_to_loc(); + +#endif /*NO_GRAPHICS*/ + #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index c73597acd5c..87b85c7f0e7 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -34,9 +34,13 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag //Manual Move Generator function e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - int block_id = manual_move_global->manual_move_info.blockID; - t_pl_loc to = manual_move_global->manual_move_info.to_location; + int block_id; + t_pl_loc to; + +#ifndef NO_GRAPHICS + block_id = return_block_id(); + to = return_to_loc(); +#endif /*NO_GRAPHICS*/ ClusterBlockId b_from = ClusterBlockId(block_id); diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 8f2c4bb7eaf..ddd6605ee56 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1328,13 +1328,12 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; //When manual move toggle button is active, the manual move window asks the user for input. - ManualMovesGlobals* manual_move_global = get_manual_moves_global(); - if (manual_move_global->manual_move_flag) { #ifndef NO_GRAPHICS + t_draw_state* draw_state = get_draw_state_vars(); + if (draw_state->manual_moves_global.manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); #endif /*NO_GRAPHICS*/ - create_move_outcome = manual_move_generator.propose_move( blocks_affected, move_type, rlim, placer_opts, criticalities); } else { @@ -1428,15 +1427,14 @@ static e_move_result try_swap(const t_annealing_state* state, move_outcome = assess_swap(delta_c, state->t); //Updates the manaul_move_global members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. - if (manual_move_global->manual_move_flag) { - update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, - move_outcome); #ifndef NO_GRAPHICS + if (draw_state->manual_moves_global.manual_move_flag) { + update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); -#endif /*NO_GRAPHICS*/ //User accepts or rejects the move. - move_outcome = manual_move_global->manual_move_info.user_move_outcome; + move_outcome = draw_state->manual_moves_global.manual_move_info.user_move_outcome; } +#endif /*NO_GRAPHICS*/ if (move_outcome == ACCEPTED) { costs->cost += delta_c; @@ -1475,7 +1473,7 @@ static e_move_result try_swap(const t_annealing_state* state, //Highlights the new block when manual move is selected. #ifndef NO_GRAPHICS - highlight_new_block_location(manual_move_global->manual_move_flag); + highlight_new_block_location(); #endif /*NO_GRPAHICS*/ } else { From f213797abafa19d47e2cfb72c5e83488b2175fe1 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 26 Jul 2021 21:06:07 -0400 Subject: [PATCH 38/46] Changed position of NO_GRAPHICS to accomodate t_draw_state struct --- vpr/src/place/place.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index ddd6605ee56..0657f810266 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1333,7 +1333,6 @@ static e_move_result try_swap(const t_annealing_state* state, if (draw_state->manual_moves_global.manual_move_flag) { draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); -#endif /*NO_GRAPHICS*/ create_move_outcome = manual_move_generator.propose_move( blocks_affected, move_type, rlim, placer_opts, criticalities); } else { @@ -1341,6 +1340,7 @@ static e_move_result try_swap(const t_annealing_state* state, create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } +#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); From fc2f48215cc594c04ec6c9456060d569a2820033 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 28 Jul 2021 11:11:47 -0400 Subject: [PATCH 39/46] Changed the manual move flag in place.cpp --- vpr/src/draw/manual_moves.cpp | 4 ++-- vpr/src/draw/manual_moves.h | 4 +++- vpr/src/place/place.cpp | 28 +++++++++++++++++----------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 22b27e6bebd..7dba7cc1079 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -184,11 +184,11 @@ bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { return true; } -void get_manual_move_flag() { +bool get_manual_move_flag() { t_draw_state* draw_state = get_draw_state_vars(); GObject* manual_moves = application.get_object("manualMove"); - //return gtk_toggle_button_get_active((GtkToggleButton*) manual_moves); draw_state->manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); + return draw_state->manual_moves_global.manual_move_flag; } void cost_summary_dialog() { diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index a628125a475..7c0c2f0eb41 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -62,8 +62,10 @@ struct ManualMovesGlobals { /** * @brief Gets the state of the manual moves togle button and assigns it to the manual_move_flag in the ManualMovesGlobal struct. + * + * @return True if the toggle button is active, false otherwise. */ -void get_manual_move_flag(); +bool get_manual_move_flag(); /** * @brief Draws the manual move window. diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 0657f810266..4045352beb9 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -273,7 +273,8 @@ static e_move_result try_swap(const t_annealing_state* state, const t_placer_opts& placer_opts, MoveTypeStat& move_type_stat, const t_place_algorithm& place_algorithm, - float timing_bb_factor); + float timing_bb_factor, + bool manual_move_flag); static void check_place(const t_placer_costs& costs, const PlaceDelayModel* delay_model, @@ -1035,12 +1036,14 @@ static void placement_inner_loop(const t_annealing_state* state, inner_crit_iter_count = 1; + bool manual_move_flag = false; + /* Inner loop begins */ for (inner_iter = 0; inner_iter < state->move_lim; inner_iter++) { e_move_result swap_result = try_swap(state, costs, move_generator, manual_move_generator, timing_info, pin_timing_invalidator, blocks_affected, delay_model, criticalities, setup_slacks, - placer_opts, move_type_stat, place_algorithm, timing_bb_factor); + placer_opts, move_type_stat, place_algorithm, timing_bb_factor, manual_move_flag); if (swap_result == ACCEPTED) { /* Move was accepted. Update statistics that are useful for the annealing schedule. */ @@ -1180,12 +1183,14 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t int move_lim = std::min(state->move_lim_max, (int)cluster_ctx.clb_nlist.blocks().size()); + bool manual_move_flag = false; + for (int i = 0; i < move_lim; i++) { #ifndef NO_GRAPHICS //Checks manual move flag for manual move feature t_draw_state* draw_state = get_draw_state_vars(); if (draw_state->show_graphics) - get_manual_move_flag(); + manual_move_flag = get_manual_move_flag(); #endif /*NO_GRAPHICS*/ //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack @@ -1193,7 +1198,7 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t manual_move_generator, timing_info, pin_timing_invalidator, blocks_affected, delay_model, criticalities, setup_slacks, placer_opts, move_type_stat, placer_opts.place_algorithm, - REWARD_BB_TIMING_RELATIVE_WEIGHT); + REWARD_BB_TIMING_RELATIVE_WEIGHT, manual_move_flag); if (swap_result == ACCEPTED) { num_accepted++; @@ -1289,7 +1294,8 @@ static e_move_result try_swap(const t_annealing_state* state, const t_placer_opts& placer_opts, MoveTypeStat& move_type_stat, const t_place_algorithm& place_algorithm, - float timing_bb_factor) { + float timing_bb_factor, + bool manual_move_flag) { /* Picks some block and moves it to another spot. If this spot is * * occupied, switch the blocks. Assess the change in cost function. * * rlim is the range limiter. * @@ -1328,11 +1334,11 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; //When manual move toggle button is active, the manual move window asks the user for input. -#ifndef NO_GRAPHICS - t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->manual_moves_global.manual_move_flag) { + if (manual_move_flag) { +#ifndef NO_GRAPHICCS draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); +#endif /*NO_GRAPHICS*/ create_move_outcome = manual_move_generator.propose_move( blocks_affected, move_type, rlim, placer_opts, criticalities); } else { @@ -1340,7 +1346,6 @@ static e_move_result try_swap(const t_annealing_state* state, create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } -#endif /*NO_GRAPHICS*/ ++move_type_stat.num_moves[(int)move_type]; LOG_MOVE_STATS_PROPOSED(t, blocks_affected); @@ -1428,7 +1433,8 @@ static e_move_result try_swap(const t_annealing_state* state, //Updates the manaul_move_global members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. #ifndef NO_GRAPHICS - if (draw_state->manual_moves_global.manual_move_flag) { + if (manual_move_flag) { + t_draw_state* draw_state = get_draw_state_vars(); update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); //User accepts or rejects the move. @@ -1474,7 +1480,7 @@ static e_move_result try_swap(const t_annealing_state* state, //Highlights the new block when manual move is selected. #ifndef NO_GRAPHICS highlight_new_block_location(); -#endif /*NO_GRPAHICS*/ +#endif /*NO_GRAPHICS*/ } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); From 0f24f1c8ae91b81f09c0011a26a8768964fc312d Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 28 Jul 2021 13:41:15 -0400 Subject: [PATCH 40/46] Fixed typo in compilation guards --- vpr/src/place/place.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 4045352beb9..c0bef71bf8d 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1335,12 +1335,11 @@ static e_move_result try_swap(const t_annealing_state* state, //When manual move toggle button is active, the manual move window asks the user for input. if (manual_move_flag) { -#ifndef NO_GRAPHICCS +#ifndef NO_GRAPHICS draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); #endif /*NO_GRAPHICS*/ - create_move_outcome = manual_move_generator.propose_move( - blocks_affected, move_type, rlim, placer_opts, criticalities); } else { //Generate a new move (perturbation) used to explore the space of possible placements create_move_outcome = move_generator.propose_move(blocks_affected, From d421ed7a0af58af89685c638d28d147c13c65e9f Mon Sep 17 00:00:00 2001 From: Paula Date: Fri, 13 Aug 2021 13:20:07 -0400 Subject: [PATCH 41/46] Fixed segmentation fault caused by move_type data structure --- vpr/src/draw/manual_moves.cpp | 8 +++---- vpr/src/place/RL_agent_util.cpp | 28 +++++++++++++++++++------ vpr/src/place/manual_move_generator.cpp | 26 +++++++++++------------ vpr/src/place/move_utils.h | 3 ++- vpr/src/place/place.cpp | 12 ++++++----- 5 files changed, 48 insertions(+), 29 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index 7dba7cc1079..b6b50c4bf78 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -79,10 +79,10 @@ void draw_manual_moves_window(std::string block_id) { } void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { - int block_id; - int x_location; - int y_location; - int subtile_location; + int block_id = -1; + int x_location = -1; + int y_location = -1; + int subtile_location = -1; bool valid_input = true; t_draw_state* draw_state = get_draw_state_vars(); diff --git a/vpr/src/place/RL_agent_util.cpp b/vpr/src/place/RL_agent_util.cpp index b749a39c4cd..1108034e7cf 100644 --- a/vpr/src/place/RL_agent_util.cpp +++ b/vpr/src/place/RL_agent_util.cpp @@ -39,13 +39,17 @@ void create_move_generators(std::unique_ptr& move_generator, std: if (placer_opts.place_agent_algorithm == E_GREEDY) { VTR_LOG("Using simple RL 'Epsilon Greedy agent' for choosing move types\n"); - std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2; + std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2, karmed_bandit_agent3; if (placer_opts.place_algorithm.is_timing_driven()) { //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); + + karmed_bandit_agent3 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES, placer_opts.place_agent_epsilon); + karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); + move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent3); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_MOVE_TYPES, placer_opts.place_agent_epsilon); @@ -55,8 +59,12 @@ void create_move_generators(std::unique_ptr& move_generator, std: //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); + + karmed_bandit_agent3 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); + karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); + move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent3); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); @@ -65,14 +73,18 @@ void create_move_generators(std::unique_ptr& move_generator, std: } } else { VTR_LOG("Using simple RL 'Softmax agent' for choosing move types\n"); - std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2; + std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2, karmed_bandit_agent3; if (placer_opts.place_algorithm.is_timing_driven()) { //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); + + karmed_bandit_agent3 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES); + karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); + move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent3); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_MOVE_TYPES); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); @@ -81,8 +93,12 @@ void create_move_generators(std::unique_ptr& move_generator, std: //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); + + karmed_bandit_agent3 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); + karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); + move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent1); + manual_move_generator = std::make_unique(karmed_bandit_agent3); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 87b85c7f0e7..2119de5d88f 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -33,8 +33,8 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag } //Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { - int block_id; +e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& move_type, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { + int block_id = -1; t_pl_loc to; #ifndef NO_GRAPHICS @@ -58,18 +58,18 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); auto grid_from_type = device_ctx.grid[from.x][from.y].type; VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); + move_type = e_move_type::MANUAL_MOVE; - /* - * //Retrieving the compressed block grid for this block type - * const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; - * //Checking if the block has a compatible subtile. - * auto to_type = device_ctx.grid[to.x][to.y].type; - * auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); - * - * //No compatible subtile is found. - * if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { - * return e_create_move::ABORT; - * }*/ + //Retrieving the compressed block grid for this block type + const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; + //Checking if the block has a compatible subtile. + auto to_type = device_ctx.grid[to.x][to.y].type; + auto& compatible_subtiles = compressed_block_grid.compatible_sub_tiles_for_tile.at(to_type->index); + + //No compatible subtile is found. + if (std::find(compatible_subtiles.begin(), compatible_subtiles.end(), to.sub_tile) == compatible_subtiles.end()) { + return e_create_move::ABORT; + } e_create_move create_move = ::create_move(blocks_affected, b_from, to); return create_move; diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index 1005b554a76..fd62c2f0414 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -26,7 +26,8 @@ enum class e_move_type { CENTROID, W_MEDIAN, CRIT_UNIFORM, - FEASIBLE_REGION + FEASIBLE_REGION, + MANUAL_MOVE }; enum class e_create_move { diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index c0bef71bf8d..3cdfb1f20ce 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1189,6 +1189,7 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t #ifndef NO_GRAPHICS //Checks manual move flag for manual move feature t_draw_state* draw_state = get_draw_state_vars(); + //std::cout << &draw_state->manual_moves_global << std::endl; if (draw_state->show_graphics) manual_move_flag = get_manual_move_flag(); #endif /*NO_GRAPHICS*/ @@ -1338,12 +1339,12 @@ static e_move_result try_swap(const t_annealing_state* state, #ifndef NO_GRAPHICS draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); -#endif /*NO_GRAPHICS*/ +#endif //NO_GRAPHICS } else { //Generate a new move (perturbation) used to explore the space of possible placements - create_move_outcome = move_generator.propose_move(blocks_affected, - move_type, rlim, placer_opts, criticalities); + create_move_outcome = move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } ++move_type_stat.num_moves[(int)move_type]; @@ -1436,10 +1437,11 @@ static e_move_result try_swap(const t_annealing_state* state, t_draw_state* draw_state = get_draw_state_vars(); update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); cost_summary_dialog(); + //User accepts or rejects the move. move_outcome = draw_state->manual_moves_global.manual_move_info.user_move_outcome; } -#endif /*NO_GRAPHICS*/ +#endif //NO_GRAPHICS if (move_outcome == ACCEPTED) { costs->cost += delta_c; @@ -1479,7 +1481,7 @@ static e_move_result try_swap(const t_annealing_state* state, //Highlights the new block when manual move is selected. #ifndef NO_GRAPHICS highlight_new_block_location(); -#endif /*NO_GRAPHICS*/ +#endif //NO_GRAPHICS } else { VTR_ASSERT_SAFE(move_outcome == REJECTED); From df73c467b943a78d6dde1642074f01f1ba85c344 Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 16 Aug 2021 11:00:25 -0400 Subject: [PATCH 42/46] Changed placement of manual move move type in place.cpp, in case the user selects manual move accidentally --- vpr/src/place/manual_move_generator.cpp | 3 +-- vpr/src/place/place.cpp | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 2119de5d88f..ca91600003a 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -33,7 +33,7 @@ ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& ag } //Manual Move Generator function -e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& move_type, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { +e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { int block_id = -1; t_pl_loc to; @@ -58,7 +58,6 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); auto grid_from_type = device_ctx.grid[from.x][from.y].type; VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); - move_type = e_move_type::MANUAL_MOVE; //Retrieving the compressed block grid for this block type const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index e4a2c13a0a5..3bfde68a039 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1347,6 +1347,7 @@ static e_move_result try_swap(const t_annealing_state* state, draw_manual_moves_window(""); update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + move_type = e_move_type::MANUAL_MOVE; create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); #endif //NO_GRAPHICS } else { From 4659a04a93c23da77e59b14ba16bd8ca220f2db8 Mon Sep 17 00:00:00 2001 From: Paula Date: Sat, 21 Aug 2021 23:21:15 -0400 Subject: [PATCH 43/46] Changed code based on the changes requested from the PR --- vpr/src/draw/draw.cpp | 7 +- vpr/src/draw/draw_types.h | 2 +- vpr/src/draw/manual_moves.cpp | 130 +++++++++++------------- vpr/src/draw/manual_moves.h | 78 +++++++------- vpr/src/place/RL_agent_util.cpp | 2 - vpr/src/place/manual_move_generator.cpp | 16 ++- vpr/src/place/place.cpp | 43 ++++---- 7 files changed, 137 insertions(+), 141 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 8a934def962..c8275e910c2 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -227,7 +227,6 @@ const std::vector kelly_max_contrast_colors = { ezgl::application::settings settings("/ezgl/main.ui", "MainWindow", "MainCanvas", "org.verilogtorouting.vpr.PID" + std::to_string(vtr::get_pid()), setup_default_ezgl_callbacks); ezgl::application application(settings); -//bool mm_window = false; bool window_mode = false; bool window_point_1_collected = false; ezgl::point2d point_1(0, 0); @@ -4375,9 +4374,9 @@ static void highlight_blocks(double x, double y) { //If manual moves is activated, then user can select block from the grid. t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->manual_moves_global.manual_move_flag) { - draw_state->manual_moves_global.user_highlighted_block = true; - if (!draw_state->manual_moves_global.mm_window_is_open) { + if (draw_state->manual_moves_state.manual_move_enabled) { + draw_state->manual_moves_state.user_highlighted_block = true; + if (!draw_state->manual_moves_state.manual_move_window_is_open) { draw_manual_moves_window(std::to_string(size_t(clb_index))); } } diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index 0c344396220..52640d8e7d6 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -197,7 +197,7 @@ struct t_draw_state { int sequence_number = 0; float net_alpha = 0.1; float pres_fac = 1.; - ManualMovesGlobals manual_moves_global; + ManualMovesState manual_moves_state; std::vector list_of_breakpoints; diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index b6b50c4bf78..d0ee1073758 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -5,6 +5,7 @@ * @brief Contains the function definitions needed for manual moves feature. * * Includes the graphics/gtk function for manual moves. The Manual Move Generator class is defined manual_move_generator.h/cpp. + * The manual move feature allows the user to select a move by choosing the block to move, x position, y position, subtile position. If the placer accepts the move, the user can accept or reject the move with respect to the delta cost, delta timing and delta bounding box cost displayed on the UI. The manual move feature interacts with placement through the ManualMoveGenerator class in the manual_move_generator.cpp/h files and in the place.cpp file by checking if the manual move toggle button in the UI is active or not, and calls the function needed. */ #include "manual_moves.h" @@ -17,21 +18,21 @@ void draw_manual_moves_window(std::string block_id) { t_draw_state* draw_state = get_draw_state_vars(); - if (!draw_state->manual_moves_global.mm_window_is_open) { - draw_state->manual_moves_global.mm_window_is_open = true; + if (!draw_state->manual_moves_state.manual_move_window_is_open) { + draw_state->manual_moves_state.manual_move_window_is_open = true; //Window settings- - draw_state->manual_moves_global.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position((GtkWindow*)draw_state->manual_moves_global.manual_move_window, GTK_WIN_POS_CENTER); - gtk_window_set_title((GtkWindow*)draw_state->manual_moves_global.manual_move_window, "Manual Moves Generator"); - gtk_widget_set_name(draw_state->manual_moves_global.manual_move_window, "manual_move_window"); + draw_state->manual_moves_state.manual_move_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position((GtkWindow*)draw_state->manual_moves_state.manual_move_window, GTK_WIN_POS_CENTER); + gtk_window_set_title((GtkWindow*)draw_state->manual_moves_state.manual_move_window, "Manual Moves Generator"); + gtk_widget_set_name(draw_state->manual_moves_state.manual_move_window, "manual_move_window"); GtkWidget* grid = gtk_grid_new(); GtkWidget* block_entry = gtk_entry_new(); - if (draw_state->manual_moves_global.user_highlighted_block) { + if (draw_state->manual_moves_state.user_highlighted_block) { gtk_entry_set_text((GtkEntry*)block_entry, block_id.c_str()); - draw_state->manual_moves_global.user_highlighted_block = false; + draw_state->manual_moves_state.user_highlighted_block = false; } GtkWidget* x_position_entry = gtk_entry_new(); @@ -71,10 +72,10 @@ void draw_manual_moves_window(std::string block_id) { //connect signals g_signal_connect(calculate_cost_button, "clicked", G_CALLBACK(calculate_cost_callback), grid); - g_signal_connect(G_OBJECT(draw_state->manual_moves_global.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); + g_signal_connect(G_OBJECT(draw_state->manual_moves_state.manual_move_window), "destroy", G_CALLBACK(close_manual_moves_window), NULL); - gtk_container_add(GTK_CONTAINER(draw_state->manual_moves_global.manual_move_window), grid); - gtk_widget_show_all(draw_state->manual_moves_global.manual_move_window); + gtk_container_add(GTK_CONTAINER(draw_state->manual_moves_state.manual_move_window), grid); + gtk_widget_show_all(draw_state->manual_moves_state.manual_move_window); } } @@ -114,19 +115,19 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { } t_pl_loc to = t_pl_loc(x_location, y_location, subtile_location); - valid_input = checking_legality_conditions(ClusterBlockId(block_id), to); + valid_input = is_manual_move_legal(ClusterBlockId(block_id), to); if (valid_input) { - draw_state->manual_moves_global.manual_move_info.valid_input = true; - draw_state->manual_moves_global.manual_move_info.blockID = block_id; - draw_state->manual_moves_global.manual_move_info.x_pos = x_location; - draw_state->manual_moves_global.manual_move_info.y_pos = y_location; - draw_state->manual_moves_global.manual_move_info.subtile = subtile_location; - draw_state->manual_moves_global.manual_move_info.to_location = to; + draw_state->manual_moves_state.manual_move_info.valid_input = true; + draw_state->manual_moves_state.manual_move_info.blockID = block_id; + draw_state->manual_moves_state.manual_move_info.x_pos = x_location; + draw_state->manual_moves_state.manual_move_info.y_pos = y_location; + draw_state->manual_moves_state.manual_move_info.subtile = subtile_location; + draw_state->manual_moves_state.manual_move_info.to_location = to; //Highlighting the block deselect_all(); - ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); + ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_state.manual_move_info.blockID); draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); application.refresh_drawing(); @@ -135,11 +136,11 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid) { ezgl::press_proceed(proceed, &application); } else { - draw_state->manual_moves_global.manual_move_info.valid_input = false; + draw_state->manual_moves_state.manual_move_info.valid_input = false; } } -bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { +bool is_manual_move_legal(ClusterBlockId block_id, t_pl_loc to) { auto& cluster_ctx = g_vpr_ctx.clustering(); auto& place_ctx = g_vpr_ctx.placement(); auto& device_ctx = g_vpr_ctx.device(); @@ -184,21 +185,21 @@ bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to) { return true; } -bool get_manual_move_flag() { +bool manual_move_is_selected() { t_draw_state* draw_state = get_draw_state_vars(); GObject* manual_moves = application.get_object("manualMove"); - draw_state->manual_moves_global.manual_move_flag = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); - return draw_state->manual_moves_global.manual_move_flag; + draw_state->manual_moves_state.manual_move_enabled = gtk_toggle_button_get_active((GtkToggleButton*)manual_moves); + return draw_state->manual_moves_state.manual_move_enabled; } -void cost_summary_dialog() { +void manual_move_cost_summary_dialog() { t_draw_state* draw_state = get_draw_state_vars(); GtkWidget* dialog; GtkWidget* content_area; //Creating the dialog window dialog = gtk_dialog_new_with_buttons("Move Costs", - (GtkWindow*)draw_state->manual_moves_global.manual_move_window, + (GtkWindow*)draw_state->manual_moves_state.manual_move_window, GTK_DIALOG_DESTROY_WITH_PARENT, ("Accept"), GTK_RESPONSE_ACCEPT, @@ -206,19 +207,16 @@ void cost_summary_dialog() { GTK_RESPONSE_REJECT, NULL); - //Find function so substitute this one because it is deprecated - //gtk_widget_set_halign(gtk_dialog_get_action_area((GtkDialog*)dialog), GTK_ALIGN_CENTER); - //Create elements for the dialog and printing costs to the user. GtkWidget* title_label = gtk_label_new(NULL); gtk_label_set_markup((GtkLabel*)title_label, "Move Costs and Outcomes"); - std::string delta_cost = "Delta Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_cost) + " "; + std::string delta_cost = "Delta Cost: " + std::to_string(draw_state->manual_moves_state.manual_move_info.delta_cost) + " "; GtkWidget* delta_cost_label = gtk_label_new(delta_cost.c_str()); - std::string delta_timing = " Delta Timing: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_timing) + " "; + std::string delta_timing = " Delta Timing: " + std::to_string(draw_state->manual_moves_state.manual_move_info.delta_timing) + " "; GtkWidget* delta_timing_label = gtk_label_new(delta_timing.c_str()); - std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(draw_state->manual_moves_global.manual_move_info.delta_bounding_box) + " "; + std::string delta_bounding_box = " Delta Bounding Box Cost: " + std::to_string(draw_state->manual_moves_state.manual_move_info.delta_bounding_box) + " "; GtkWidget* delta_bounding_box_label = gtk_label_new(delta_bounding_box.c_str()); - std::string outcome = e_move_result_to_string(draw_state->manual_moves_global.manual_move_info.placer_move_outcome); + std::string outcome = e_move_result_to_string(draw_state->manual_moves_state.manual_move_info.placer_move_outcome); std::string move_outcome = " Annealing Decision: " + outcome + " "; GtkWidget* move_outcome_label = gtk_label_new(move_outcome.c_str()); GtkWidget* space_label1 = gtk_label_new(" "); @@ -238,24 +236,24 @@ void cost_summary_dialog() { gtk_widget_show_all(dialog); //Update message if user accepts the move. - std::string msg = "Manual move accepted. Block #" + std::to_string(draw_state->manual_moves_global.manual_move_info.blockID); - msg += " to location (" + std::to_string(draw_state->manual_moves_global.manual_move_info.x_pos) + ", " + std::to_string(draw_state->manual_moves_global.manual_move_info.y_pos) + ")"; + std::string msg = "Manual move accepted. Block #" + std::to_string(draw_state->manual_moves_state.manual_move_info.blockID); + msg += " to location (" + std::to_string(draw_state->manual_moves_state.manual_move_info.x_pos) + ", " + std::to_string(draw_state->manual_moves_state.manual_move_info.y_pos) + ")"; //Waiting for the user to respond to return to try_swa function. int result = gtk_dialog_run(GTK_DIALOG(dialog)); switch (result) { //If the user accepts the manual move case GTK_RESPONSE_ACCEPT: - draw_state->manual_moves_global.manual_move_info.user_move_outcome = ACCEPTED; + draw_state->manual_moves_state.manual_move_info.user_move_outcome = ACCEPTED; application.update_message(msg.c_str()); break; //If the user rejects the manual move case GTK_RESPONSE_REJECT: - draw_state->manual_moves_global.manual_move_info.user_move_outcome = REJECTED; + draw_state->manual_moves_state.manual_move_info.user_move_outcome = REJECTED; application.update_message("Manual move was rejected"); break; default: - draw_state->manual_moves_global.manual_move_info.user_move_outcome = ABORTED; + draw_state->manual_moves_state.manual_move_info.user_move_outcome = ABORTED; break; } @@ -263,37 +261,21 @@ void cost_summary_dialog() { gtk_widget_destroy(dialog); } -void highlight_new_block_location() { +void manual_move_highlight_new_block_location() { t_draw_state* draw_state = get_draw_state_vars(); - if (draw_state->manual_moves_global.manual_move_flag) { - auto& cluster_ctx = g_vpr_ctx.clustering(); - //Unselects all blocks first - deselect_all(); - //Highlighting the block - ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_global.manual_move_info.blockID); - draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); - application.refresh_drawing(); - } + auto& cluster_ctx = g_vpr_ctx.clustering(); + //Unselects all blocks first + deselect_all(); + //Highlighting the block + ClusterBlockId clb_index = ClusterBlockId(draw_state->manual_moves_state.manual_move_info.blockID); + draw_highlight_blocks_color(cluster_ctx.clb_nlist.block_type(clb_index), clb_index); + application.refresh_drawing(); } //Manual move window turns false, the window is destroyed. void close_manual_moves_window() { t_draw_state* draw_state = get_draw_state_vars(); - draw_state->manual_moves_global.mm_window_is_open = false; -} - -ManualMovesGlobals* get_manual_moves_global() { - t_draw_state* draw_state = get_draw_state_vars(); - return &draw_state->manual_moves_global; -} - -//Updates ManualMovesInfo cost members -void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { - t_draw_state* draw_state = get_draw_state_vars(); - draw_state->manual_moves_global.manual_move_info.delta_cost = d_cost; - draw_state->manual_moves_global.manual_move_info.delta_timing = d_timing; - draw_state->manual_moves_global.manual_move_info.delta_bounding_box = d_bounding_box; - draw_state->manual_moves_global.manual_move_info.placer_move_outcome = move_outcome; + draw_state->manual_moves_state.manual_move_window_is_open = false; } bool string_is_a_number(std::string block_id) { @@ -306,14 +288,24 @@ bool string_is_a_number(std::string block_id) { return true; } -int return_block_id() { - t_draw_state* draw_state = get_draw_state_vars(); - return draw_state->manual_moves_global.manual_move_info.blockID; -} -t_pl_loc return_to_loc() { + +//Updates ManualMovesInfo cost and placer move outcome variables. User_move_outcome is also updated. +e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { + t_draw_state* draw_state = get_draw_state_vars(); - return draw_state->manual_moves_global.manual_move_info.to_location; + draw_state->manual_moves_state.manual_move_info.delta_cost = d_cost; + draw_state->manual_moves_state.manual_move_info.delta_timing = d_timing; + draw_state->manual_moves_state.manual_move_info.delta_bounding_box = d_bounding_box; + draw_state->manual_moves_state.manual_move_info.placer_move_outcome = move_outcome; + + //Displays the delta cost to the user. + manual_move_cost_summary_dialog(); + //User accepts or rejects the move. + move_outcome = draw_state->manual_moves_state.manual_move_info.user_move_outcome; + return move_outcome; } + + #endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 7c0c2f0eb41..fe8307f4f29 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -28,6 +28,21 @@ * @brief ManualMovesInfo struct * * Contains information about the block, location, validity of user input, timing variables, and placer outcomes. + * + * GUI writes to: + * blockID: Stores the block ID of the block requested to move by the user. + * x_pos: Stores the x position of the block requested to move by the user. + * y_pos: Stores the y position of the block requested to move by the user. + * subtile: Stores the subtile of the block requested to move by the user. + * valid input: Stores whether the manual move is valid with respect to the user's input in the UI. + * user_move_outcome: The user determines to acceopt or reject the manual move. + * + * Placer writes to: + * delta_cost: Stores the delta cost of the manual move requested by the user. + * delta_timing: Stores the delta timing of the manual move requested by the user. + * delta_bounding_box: Stores the delta bounding box cost of the manual move requested by the user. + * to_location: Stores the x position, y position and subtile position requested by the user in a t_pl_loc variable. + * placer_move_outcome: The placer determines if the manual move requested by the user is valid. */ struct ManualMovesInfo { @@ -45,42 +60,46 @@ struct ManualMovesInfo { }; /** - * @brief ManualMovesGlobals struct + * @brief ManualMovesState struct * * Contains a ManualMovesInfo variable to store manual move data, boolean values to check the state of the windows needed and gtk manual move widow variable. + * ManualMovesInfo: Stores the manual move information from the user's input and the placer's/user's outcome to the move. + * manual_move_window_is_open: Stores whether the manual move window is open or not. + * user_highlighted_block: Stores whether user highlighted block in UI instead of entering the block ID manually. + * manual_move_window: GtkWindow for the manual move. In this window the user inputs the block ID and to position of the block to move. */ -struct ManualMovesGlobals { +struct ManualMovesState { ManualMovesInfo manual_move_info; - bool mm_window_is_open = false; + bool manual_move_window_is_open = false; bool user_highlighted_block = false; - bool manual_move_flag = false; + bool manual_move_enabled = false; GtkWidget* manual_move_window; }; /** manual moves functions **/ /** - * @brief Gets the state of the manual moves togle button and assigns it to the manual_move_flag in the ManualMovesGlobal struct. + * @brief Gets the state of the manual moves togle button and assigns it to the manual_move_enabled in the ManualMovesState struct. * * @return True if the toggle button is active, false otherwise. */ -bool get_manual_move_flag(); +bool manual_move_is_selected(); /** * @brief Draws the manual move window. * * Window prompts the user for input: block id/name, s position, y position, and subtile position. - * @param block_id: The block id selected/highlighted by the user. + * @param block_id: The block id is passed in if the user decides to highlight the block in the UI. If the user decides to manually input the block ID in the manual move window, the string will be empty and the block ID will later be assigned to ManualMovesState struct. */ void draw_manual_moves_window(std::string block_id); /** * @brief Evaluates if the user input is valid and allowed. * - * Sets the members from the ManualMovesGlobals global variable to their respective values (block id and locations). - * @param GtkWidget* widget: Needed for gtk functions. - * @param GtkWidget* grid: Needed to extract members from the manual move window. + * Sets the members from the ManualMovesState manual_moves_state variable to their respective values (block id and locations). + * @param GtkWidget* widget: Passed in for gtk callback functions (Needed due to the GTK function protoype, in GTK documentation). + * @param GtkWidget* grid: The grid is used to extract the user input from the manual move window, to later assign to the ManualMovesState variable. */ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); @@ -93,21 +112,21 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); * * @return True if all conditions are met, false otherwise. */ -bool checking_legality_conditions(ClusterBlockId block_id, t_pl_loc to); +bool is_manual_move_legal(ClusterBlockId block_id, t_pl_loc to); /** * @brief Draws the cost summary dialog. * * Window displays the delta cost, delta timing, delta bounding box timing, annealing decision to the user. Waits for the user to ACCEPT/REJECT the manual move. */ -void cost_summary_dialog(); +void manual_move_cost_summary_dialog(); /** * @brief Highlights new block location * - * Highlights block in the new location if the manual move flag is active and the user accepted the manual move. + * Highlights block in the new location if the manual move is active and the user accepted the manual move. */ -void highlight_new_block_location(); +void manual_move_highlight_new_block_location(); /** * @brief Disables the mm_window_is_open boolean and destroys the window @@ -115,38 +134,23 @@ void highlight_new_block_location(); void close_manual_moves_window(); /** - * @brief Gets the manual_moves_global variables in manual_move.cpp. + * @brief Checks if the given string is a number * - * @return The manual_moves_global variable. + * @return True if the string only contains numbers, false otherwise. */ -ManualMovesGlobals* get_manual_moves_global(); +bool string_is_a_number(std::string block_id); /** - * @brief Updates the ManualMovesGlobals global veriable members. + * @brief Updates the ManualMovesState variable members. * * @param d_cost: Delta cost for cost summary dialog function. * @param d_timing: Delta timing for cost summary dialog function. * @param d_bounding_box: Delta bounding box for cost summary dialog function. * @param move_outcome: Move result from placement for cost summary dialog function. - */ -void update_manual_move_costs(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); - -/** - * @brief Checks if the given string is a number - * - * @return True if the string only contains numbers, false otherwise. - */ -bool string_is_a_number(std::string block_id); - -/** - * @brief Returns the block requested by the user for manual moves. - */ -int return_block_id(); - -/** - * @brief Returns the to location requested by the user for manual moves. - */ -t_pl_loc return_to_loc(); + * + * Helper function used in place.cpp. The ManualMovesState variable are updated and the manual_move_cost_summary_dialog is called to display the cost members to the user in the UI and waits for the user to either ACCPET/REJECT the manual move. +*/ +e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); #endif /*NO_GRAPHICS*/ diff --git a/vpr/src/place/RL_agent_util.cpp b/vpr/src/place/RL_agent_util.cpp index 1108034e7cf..5f237e64673 100644 --- a/vpr/src/place/RL_agent_util.cpp +++ b/vpr/src/place/RL_agent_util.cpp @@ -14,7 +14,6 @@ void create_move_generators(std::unique_ptr& move_generator, std: VTR_LOG("Probability of Critical_uniform_move : %f \n", placer_opts.place_static_move_prob[6]); move_generator = std::make_unique(placer_opts.place_static_move_prob); move_generator2 = std::make_unique(placer_opts.place_static_move_prob); - //manual_move_generator = std::make_unique(placer_opts.place_static_move_prob); } else { //Non-timing driven placement VTR_LOG("Using static probabilities for choosing each move type\n"); VTR_LOG("Probability of Uniform_move : %f \n", placer_opts.place_static_notiming_move_prob[0]); @@ -22,7 +21,6 @@ void create_move_generators(std::unique_ptr& move_generator, std: VTR_LOG("Probability of Centroid_move : %f \n", placer_opts.place_static_notiming_move_prob[2]); move_generator = std::make_unique(placer_opts.place_static_notiming_move_prob); move_generator2 = std::make_unique(placer_opts.place_static_notiming_move_prob); - //manual_move_generator = std::make_unique(placer_opts.place_static_notiming_move_prob); } } else { //RL based placement /* For the non timing driven placecment: the agent has a single state * diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index ca91600003a..8df763c3691 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -2,12 +2,17 @@ * @file manual_move_generator.cpp * @author Paula Perdomo * @date 2021-07-19 - * @brief Contains the ManualMoveGenerator class memeber definitions. + * @brief Contains the ManualMoveGenerator class memeber definitions. The ManualMoveGenerator class inherits from the MoveGenerator class. The class contains a propose_move function that checks if the block requested to move by the user exists and determines whether the manual move is VALID/ABORTED by the placer. If the manual move is determined VALID, the move is created. A manual move is ABORTED if the block requested is not found or movable and if there aren't any compatible subtiles. */ #include "manual_move_generator.h" #include "manual_moves.h" +#ifndef NO_GRAPHICS +#include "draw.h" +#endif //NO_GRAPHICS + + ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { avail_moves.push_back(std::move(std::make_unique())); avail_moves.push_back(std::move(std::make_unique())); @@ -38,9 +43,10 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ t_pl_loc to; #ifndef NO_GRAPHICS - block_id = return_block_id(); - to = return_to_loc(); -#endif /*NO_GRAPHICS*/ + t_draw_state* draw_state = get_draw_state_vars(); + block_id = draw_state->manual_moves_state.manual_move_info.blockID; + to = draw_state->manual_moves_state.manual_move_info.to_location; +#endif //NO_GRAPHICS ClusterBlockId b_from = ClusterBlockId(block_id); @@ -58,7 +64,7 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); auto grid_from_type = device_ctx.grid[from.x][from.y].type; VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); - + //Retrieving the compressed block grid for this block type const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; //Checking if the block has a compatible subtile. diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 3bfde68a039..a957b9469e2 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -274,7 +274,7 @@ static e_move_result try_swap(const t_annealing_state* state, MoveTypeStat& move_type_stat, const t_place_algorithm& place_algorithm, float timing_bb_factor, - bool manual_move_flag); + bool manual_move_enabled); static void check_place(const t_placer_costs& costs, const PlaceDelayModel* delay_model, @@ -1043,14 +1043,14 @@ static void placement_inner_loop(const t_annealing_state* state, inner_crit_iter_count = 1; - bool manual_move_flag = false; + bool manual_move_enabled = false; /* Inner loop begins */ for (inner_iter = 0; inner_iter < state->move_lim; inner_iter++) { e_move_result swap_result = try_swap(state, costs, move_generator, manual_move_generator, timing_info, pin_timing_invalidator, blocks_affected, delay_model, criticalities, setup_slacks, - placer_opts, move_type_stat, place_algorithm, timing_bb_factor, manual_move_flag); + placer_opts, move_type_stat, place_algorithm, timing_bb_factor, manual_move_enabled); if (swap_result == ACCEPTED) { /* Move was accepted. Update statistics that are useful for the annealing schedule. */ @@ -1190,15 +1190,15 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t int move_lim = std::min(state->move_lim_max, (int)cluster_ctx.clb_nlist.blocks().size()); - bool manual_move_flag = false; + bool manual_move_enabled = false; for (int i = 0; i < move_lim; i++) { #ifndef NO_GRAPHICS //Checks manual move flag for manual move feature t_draw_state* draw_state = get_draw_state_vars(); - //std::cout << &draw_state->manual_moves_global << std::endl; - if (draw_state->show_graphics) - manual_move_flag = get_manual_move_flag(); + if(draw_state->show_graphics) { + manual_move_enabled = manual_move_is_selected(); + } #endif /*NO_GRAPHICS*/ //Will not deploy setup slack analysis, so omit crit_exponenet and setup_slack @@ -1206,7 +1206,7 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t manual_move_generator, timing_info, pin_timing_invalidator, blocks_affected, delay_model, criticalities, setup_slacks, placer_opts, move_type_stat, placer_opts.place_algorithm, - REWARD_BB_TIMING_RELATIVE_WEIGHT, manual_move_flag); + REWARD_BB_TIMING_RELATIVE_WEIGHT, manual_move_enabled); if (swap_result == ACCEPTED) { num_accepted++; @@ -1303,7 +1303,7 @@ static e_move_result try_swap(const t_annealing_state* state, MoveTypeStat& move_type_stat, const t_place_algorithm& place_algorithm, float timing_bb_factor, - bool manual_move_flag) { + bool manual_move_enabled) { /* Picks some block and moves it to another spot. If this spot is * * occupied, switch the blocks. Assess the change in cost function. * * rlim is the range limiter. * @@ -1342,13 +1342,13 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; //When manual move toggle button is active, the manual move window asks the user for input. - if (manual_move_flag) { + if (manual_move_enabled) { #ifndef NO_GRAPHICS - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - move_type = e_move_type::MANUAL_MOVE; - create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + move_type = e_move_type::MANUAL_MOVE; + create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); #endif //NO_GRAPHICS } else { //Generate a new move (perturbation) used to explore the space of possible placements @@ -1439,15 +1439,10 @@ static e_move_result try_swap(const t_annealing_state* state, /* 1 -> move accepted, 0 -> rejected. */ move_outcome = assess_swap(delta_c, state->t); - //Updates the manaul_move_global members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. + //Updates the manual_move_state members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. #ifndef NO_GRAPHICS - if (manual_move_flag) { - t_draw_state* draw_state = get_draw_state_vars(); - update_manual_move_costs(delta_c, timing_delta_c, bb_delta_c, move_outcome); - cost_summary_dialog(); - - //User accepts or rejects the move. - move_outcome = draw_state->manual_moves_global.manual_move_info.user_move_outcome; + if (manual_move_enabled) { + move_outcome = pl_do_manual_move(delta_c, timing_delta_c, bb_delta_c, move_outcome); } #endif //NO_GRAPHICS @@ -1488,7 +1483,9 @@ static e_move_result try_swap(const t_annealing_state* state, //Highlights the new block when manual move is selected. #ifndef NO_GRAPHICS - highlight_new_block_location(); + if(manual_move_enabled) { + manual_move_highlight_new_block_location(); + } #endif //NO_GRAPHICS } else { From 59bf855e2f0d1c453c0124dca835701f5ad07107 Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 24 Aug 2021 23:54:55 -0400 Subject: [PATCH 44/46] Changed move generator file definitions with manual moves. --- vpr/src/draw/manual_moves.cpp | 11 ++++----- vpr/src/draw/manual_moves.h | 2 +- vpr/src/place/RL_agent_util.cpp | 28 +++------------------- vpr/src/place/RL_agent_util.h | 2 +- vpr/src/place/manual_move_generator.cpp | 29 ++--------------------- vpr/src/place/manual_move_generator.h | 8 ------- vpr/src/place/move_utils.cpp | 5 ++-- vpr/src/place/move_utils.h | 2 +- vpr/src/place/place.cpp | 31 +++++++++++++------------ 9 files changed, 31 insertions(+), 87 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index d0ee1073758..d8d1c4be69b 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -207,6 +207,8 @@ void manual_move_cost_summary_dialog() { GTK_RESPONSE_REJECT, NULL); + gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)draw_state->manual_moves_state.manual_move_window); + //Create elements for the dialog and printing costs to the user. GtkWidget* title_label = gtk_label_new(NULL); gtk_label_set_markup((GtkLabel*)title_label, "Move Costs and Outcomes"); @@ -288,24 +290,19 @@ bool string_is_a_number(std::string block_id) { return true; } - - -//Updates ManualMovesInfo cost and placer move outcome variables. User_move_outcome is also updated. +//Updates ManualMovesInfo cost and placer move outcome variables. User_move_outcome is also updated. e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome) { - t_draw_state* draw_state = get_draw_state_vars(); draw_state->manual_moves_state.manual_move_info.delta_cost = d_cost; draw_state->manual_moves_state.manual_move_info.delta_timing = d_timing; draw_state->manual_moves_state.manual_move_info.delta_bounding_box = d_bounding_box; draw_state->manual_moves_state.manual_move_info.placer_move_outcome = move_outcome; - //Displays the delta cost to the user. + //Displays the delta cost to the user. manual_move_cost_summary_dialog(); //User accepts or rejects the move. move_outcome = draw_state->manual_moves_state.manual_move_info.user_move_outcome; return move_outcome; } - - #endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index fe8307f4f29..84e3ebb53e4 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -149,7 +149,7 @@ bool string_is_a_number(std::string block_id); * @param move_outcome: Move result from placement for cost summary dialog function. * * Helper function used in place.cpp. The ManualMovesState variable are updated and the manual_move_cost_summary_dialog is called to display the cost members to the user in the UI and waits for the user to either ACCPET/REJECT the manual move. -*/ + */ e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); #endif /*NO_GRAPHICS*/ diff --git a/vpr/src/place/RL_agent_util.cpp b/vpr/src/place/RL_agent_util.cpp index 5f237e64673..171b710e99d 100644 --- a/vpr/src/place/RL_agent_util.cpp +++ b/vpr/src/place/RL_agent_util.cpp @@ -1,7 +1,7 @@ #include "RL_agent_util.h" #include "manual_move_generator.h" -void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, std::unique_ptr& manual_move_generator, const t_placer_opts& placer_opts, int move_lim) { +void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, const t_placer_opts& placer_opts, int move_lim) { if (placer_opts.RL_agent_placement == false) { if (placer_opts.place_algorithm.is_timing_driven()) { VTR_LOG("Using static probabilities for choosing each move type\n"); @@ -37,18 +37,12 @@ void create_move_generators(std::unique_ptr& move_generator, std: if (placer_opts.place_agent_algorithm == E_GREEDY) { VTR_LOG("Using simple RL 'Epsilon Greedy agent' for choosing move types\n"); - std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2, karmed_bandit_agent3; + std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2; if (placer_opts.place_algorithm.is_timing_driven()) { //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); - - karmed_bandit_agent3 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES, placer_opts.place_agent_epsilon); - karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); - move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent3); - //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); @@ -57,13 +51,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); - - karmed_bandit_agent3 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); - karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); - move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent3); - //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); @@ -71,18 +59,13 @@ void create_move_generators(std::unique_ptr& move_generator, std: } } else { VTR_LOG("Using simple RL 'Softmax agent' for choosing move types\n"); - std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2, karmed_bandit_agent3; + std::unique_ptr karmed_bandit_agent1, karmed_bandit_agent2; if (placer_opts.place_algorithm.is_timing_driven()) { //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); - - karmed_bandit_agent3 = std::make_unique(NUM_PL_1ST_STATE_MOVE_TYPES); - karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); - move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent3); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_MOVE_TYPES); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); @@ -91,12 +74,7 @@ void create_move_generators(std::unique_ptr& move_generator, std: //agent's 1st state karmed_bandit_agent1 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim); - - karmed_bandit_agent3 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); - karmed_bandit_agent3->set_step(placer_opts.place_agent_gamma, move_lim); - move_generator = std::make_unique(karmed_bandit_agent1); - manual_move_generator = std::make_unique(karmed_bandit_agent3); //agent's 2nd state karmed_bandit_agent2 = std::make_unique(NUM_PL_NONTIMING_MOVE_TYPES); karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim); diff --git a/vpr/src/place/RL_agent_util.h b/vpr/src/place/RL_agent_util.h index bb52b4e365f..ebfee697850 100644 --- a/vpr/src/place/RL_agent_util.h +++ b/vpr/src/place/RL_agent_util.h @@ -19,7 +19,7 @@ enum e_agent_state { * It returns a unique pointer for each move generator in move_generator and move_generator2 * move_lim: represents the num of moves per temp. */ -void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, std::unique_ptr& manual_move_generator, const t_placer_opts& placer_opts, int move_lim); +void create_move_generators(std::unique_ptr& move_generator, std::unique_ptr& move_generator2, const t_placer_opts& placer_opts, int move_lim); /** * @brief copy one of the available move_generators to be the current move_generator that would be used in the placement based on the placer_options and the agent state diff --git a/vpr/src/place/manual_move_generator.cpp b/vpr/src/place/manual_move_generator.cpp index 8df763c3691..cb482f0cbce 100644 --- a/vpr/src/place/manual_move_generator.cpp +++ b/vpr/src/place/manual_move_generator.cpp @@ -9,34 +9,9 @@ #include "manual_moves.h" #ifndef NO_GRAPHICS -#include "draw.h" +# include "draw.h" #endif //NO_GRAPHICS - -ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - - karmed_bandit_agent = std::move(agent); -} - -ManualMoveGenerator::ManualMoveGenerator(std::unique_ptr& agent) { - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - avail_moves.push_back(std::move(std::make_unique())); - - karmed_bandit_agent = std::move(agent); -} - //Manual Move Generator function e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/) { int block_id = -1; @@ -64,7 +39,7 @@ e_create_move ManualMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ auto cluster_from_type = cluster_ctx.clb_nlist.block_type(b_from); auto grid_from_type = device_ctx.grid[from.x][from.y].type; VTR_ASSERT(is_tile_compatible(grid_from_type, cluster_from_type)); - + //Retrieving the compressed block grid for this block type const auto& compressed_block_grid = place_ctx.compressed_block_grids[cluster_from_type->index]; //Checking if the block has a compatible subtile. diff --git a/vpr/src/place/manual_move_generator.h b/vpr/src/place/manual_move_generator.h index 8cc2cdf100d..863ebc71c8c 100644 --- a/vpr/src/place/manual_move_generator.h +++ b/vpr/src/place/manual_move_generator.h @@ -25,15 +25,7 @@ * Manual Move Generator, needed for swapping blocks requested by the user. */ class ManualMoveGenerator : public MoveGenerator { - private: - std::vector> avail_moves; // list of pointers to the available move generators (the different move types) - std::unique_ptr karmed_bandit_agent; // a pointer to the specific agent used (e.g. Softmax) - public: - //Constructors using a pointer to the agent used - ManualMoveGenerator(std::unique_ptr& agent); - ManualMoveGenerator(std::unique_ptr& agent); - //Evaluates if move is successful and legal or unable to do. e_create_move propose_move(t_pl_blocks_to_be_moved& blocks_affected, e_move_type& /*move_type*/, float /*rlim*/, const t_placer_opts& /*placer_opts*/, const PlacerCriticalities* /*criticalities*/); }; diff --git a/vpr/src/place/move_utils.cpp b/vpr/src/place/move_utils.cpp index 929a6780943..8822b8b8db3 100644 --- a/vpr/src/place/move_utils.cpp +++ b/vpr/src/place/move_utils.cpp @@ -731,14 +731,15 @@ bool find_to_loc_centroid(t_logical_block_type_ptr blk_type, } //Array of move type strings -static const std::array move_type_strings = { +static const std::array move_type_strings = { "Uniform", "Median", "W. Centroid", "Centroid", "W. Median", "Crit. Uniform", - "Feasible Region"}; + "Feasible Region", + "Manual Move"}; //To convert enum move type to string std::string move_type_to_string(e_move_type move) { diff --git a/vpr/src/place/move_utils.h b/vpr/src/place/move_utils.h index fd62c2f0414..3b0f01f9bcb 100644 --- a/vpr/src/place/move_utils.h +++ b/vpr/src/place/move_utils.h @@ -27,7 +27,7 @@ enum class e_move_type { W_MEDIAN, CRIT_UNIFORM, FEASIBLE_REGION, - MANUAL_MOVE + MANUAL_MOVE, }; enum class e_create_move { diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index a957b9469e2..1cb1ef4fc5d 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -462,6 +462,8 @@ void try_place(const t_placer_opts& placer_opts, std::unique_ptr placer_criticalities; std::unique_ptr pin_timing_invalidator; + manual_move_generator = std::make_unique(); + t_pl_blocks_to_be_moved blocks_affected( cluster_ctx.clb_nlist.blocks().size()); @@ -491,8 +493,7 @@ void try_place(const t_placer_opts& placer_opts, * pow(cluster_ctx.clb_nlist.blocks().size(), 1.3333)); //create the move generator based on the chosen strategy - create_move_generators(move_generator, move_generator2, - manual_move_generator, placer_opts, move_lim); + create_move_generators(move_generator, move_generator2, placer_opts, move_lim); width_fac = placer_opts.place_chan_width; @@ -699,12 +700,12 @@ void try_place(const t_placer_opts& placer_opts, //allocate move type statistics vectors MoveTypeStat move_type_stat; - move_type_stat.num_moves.resize(placer_opts.place_static_move_prob.size(), + move_type_stat.num_moves.resize(placer_opts.place_static_move_prob.size() + 1, 0); move_type_stat.accepted_moves.resize( - placer_opts.place_static_move_prob.size(), 0); + placer_opts.place_static_move_prob.size() + 1, 0); move_type_stat.aborted_moves.resize( - placer_opts.place_static_move_prob.size(), 0); + placer_opts.place_static_move_prob.size() + 1, 0); /* Get the first range limiter */ first_rlim = (float)max(device_ctx.grid.width() - 1, @@ -1196,7 +1197,7 @@ static float starting_t(const t_annealing_state* state, t_placer_costs* costs, t #ifndef NO_GRAPHICS //Checks manual move flag for manual move feature t_draw_state* draw_state = get_draw_state_vars(); - if(draw_state->show_graphics) { + if (draw_state->show_graphics) { manual_move_enabled = manual_move_is_selected(); } #endif /*NO_GRAPHICS*/ @@ -1342,13 +1343,13 @@ static e_move_result try_swap(const t_annealing_state* state, e_create_move create_move_outcome; //When manual move toggle button is active, the manual move window asks the user for input. - if (manual_move_enabled) { + if (manual_move_enabled) { #ifndef NO_GRAPHICS - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - move_type = e_move_type::MANUAL_MOVE; - create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + move_type = e_move_type::MANUAL_MOVE; + create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); #endif //NO_GRAPHICS } else { //Generate a new move (perturbation) used to explore the space of possible placements @@ -1442,7 +1443,7 @@ static e_move_result try_swap(const t_annealing_state* state, //Updates the manual_move_state members and displays costs to the user to decide whether to ACCEPT/REJECT manual move. #ifndef NO_GRAPHICS if (manual_move_enabled) { - move_outcome = pl_do_manual_move(delta_c, timing_delta_c, bb_delta_c, move_outcome); + move_outcome = pl_do_manual_move(delta_c, timing_delta_c, bb_delta_c, move_outcome); } #endif //NO_GRAPHICS @@ -1483,9 +1484,9 @@ static e_move_result try_swap(const t_annealing_state* state, //Highlights the new block when manual move is selected. #ifndef NO_GRAPHICS - if(manual_move_enabled) { - manual_move_highlight_new_block_location(); - } + if (manual_move_enabled) { + manual_move_highlight_new_block_location(); + } #endif //NO_GRAPHICS } else { From 464f7da1beaae41cebedd62d344ea7bb13c99e55 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 1 Sep 2021 09:25:24 -0400 Subject: [PATCH 45/46] Added another helper file for place.cpp --- doc/src/vpr/graphics.rst | 26 ++++++++++++++++++++++++++ vpr/src/draw/manual_moves.cpp | 8 ++++++++ vpr/src/draw/manual_moves.h | 14 +++++++++----- vpr/src/place/place.cpp | 6 +----- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/doc/src/vpr/graphics.rst b/doc/src/vpr/graphics.rst index 780b223e0b0..103f32ccba2 100644 --- a/doc/src/vpr/graphics.rst +++ b/doc/src/vpr/graphics.rst @@ -213,4 +213,30 @@ Button Description Table | | | | FPGA | +-------------------+-------------------+------------------------------+------------------------------+ +Manual Moves +------------ + +The manual moves feature allows the user to specify the next move in placement. If the move is legal, blocks are swapped and the new move is shown on the architecture. + +.. figure:: https://www.verilogtorouting.org/img/manual_move_toggle_button.png + :align: center + +To enable the feature, activate the Manual Move toggle button and press Proceed. Alternatively, the user can active the Manual Move toggle button and click on the block to be moved. + +.. figure:: https://www.verilogtorouting.org/img/draw_manual_moves_window.png + :align: center + +On the manual move window, the user can specify the Block ID/Block name of the block to move and the To location, with the x position, y position and subtile position. For the manual move to be valid: + +- The To location requested by the user should be within the grid's dimensions. +- The block to be moved is found, valid and not fixed. +- The blocks to be swapped are compatible. +- The location choosen by the user is different from the block's current location. + +If the manual move is legal, the cost summary window will display the delta cost, delta timing, delta bounding box cost and the placer's annealing decision that would result from this move. + +.. figure:: https://www.verilogtorouting.org/img/manual_move_cost_dialog.png + :align: center + +The user can Accept or Reject the manual move based on the values provided. If accepted the block's new location is shown. diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index d8d1c4be69b..b112d998377 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -305,4 +305,12 @@ e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_boundin return move_outcome; } +e_create_move manual_move_display_and_propose(ManualMoveGenerator& manual_move_generator, t_pl_blocks_to_be_moved& blocks_affected, e_move_type& move_type, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities) { + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + move_type = e_move_type::MANUAL_MOVE; + return manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); +} + + #endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index 84e3ebb53e4..b10edc9cdbe 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -4,7 +4,7 @@ * @date 2021-07-19 * @brief Contains the function prototypes needed for manual moves feature. * - * Includes the data structures sed and gtk function for manual moves. The Manual Move Generator class is defined manual_move_generator.h/cpp. + * Includes the data structures and gtk function for manual moves. The Manual Move Generator class is defined manual_move_generator.h/cpp. */ #ifndef MANUAL_MOVES_H @@ -15,6 +15,7 @@ # include "ezgl/application.hpp" # include "ezgl/graphics.hpp" +# include "manual_move_generator.h" # include "move_utils.h" # include @@ -30,7 +31,7 @@ * Contains information about the block, location, validity of user input, timing variables, and placer outcomes. * * GUI writes to: - * blockID: Stores the block ID of the block requested to move by the user. + * blockID: Stores the block ID of the block requested to move by the user. This block is the from block in the move generator. * x_pos: Stores the x position of the block requested to move by the user. * y_pos: Stores the y position of the block requested to move by the user. * subtile: Stores the subtile of the block requested to move by the user. @@ -89,7 +90,7 @@ bool manual_move_is_selected(); /** * @brief Draws the manual move window. * - * Window prompts the user for input: block id/name, s position, y position, and subtile position. + * Window prompts the user for input: block id/name used as the from block in the move generator, x position, y position, and subtile position. * @param block_id: The block id is passed in if the user decides to highlight the block in the UI. If the user decides to manually input the block ID in the manual move window, the string will be empty and the block ID will later be assigned to ManualMovesState struct. */ void draw_manual_moves_window(std::string block_id); @@ -107,7 +108,7 @@ void calculate_cost_callback(GtkWidget* /*widget*/, GtkWidget* grid); * @brief In -detail checking of the user's input. * * Checks if the user input is between the grid's dimensions, block comptaibility, if the block requested to move is valid, if the block is fixed, and if the curent location of the block is different from the location requested by the user. - * @param block_id: The ID of the block to move. + * @param block_id: The ID of the block to move used as the from block in the move generator). * @param to: Location of where the user wants to move the block. * * @return True if all conditions are met, false otherwise. @@ -129,7 +130,7 @@ void manual_move_cost_summary_dialog(); void manual_move_highlight_new_block_location(); /** - * @brief Disables the mm_window_is_open boolean and destroys the window + * @brief Disables the manual_move_window_is_open boolean and destroys the window */ void close_manual_moves_window(); @@ -152,6 +153,9 @@ bool string_is_a_number(std::string block_id); */ e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_bounding_box, e_move_result& move_outcome); +e_create_move manual_move_display_and_propose(ManualMoveGenerator& manual_move_generator, t_pl_blocks_to_be_moved& blocks_affected, e_move_type& move_type, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities); + + #endif /*NO_GRAPHICS*/ #endif /* MANUAL_MOVES_H */ diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 1cb1ef4fc5d..f07178e1541 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1345,11 +1345,7 @@ static e_move_result try_swap(const t_annealing_state* state, //When manual move toggle button is active, the manual move window asks the user for input. if (manual_move_enabled) { #ifndef NO_GRAPHICS - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - - move_type = e_move_type::MANUAL_MOVE; - create_move_outcome = manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + create_move_outcome = manual_move_display_and_propose(manual_move_generator, blocks_affected, move_type, rlim, placer_opts, criticalities); #endif //NO_GRAPHICS } else { //Generate a new move (perturbation) used to explore the space of possible placements From 16d4c5b55793e0d50fb5530baba96d08e710c890 Mon Sep 17 00:00:00 2001 From: Paula Date: Wed, 1 Sep 2021 09:29:00 -0400 Subject: [PATCH 46/46] Formatting code --- vpr/src/draw/manual_moves.cpp | 9 ++++----- vpr/src/draw/manual_moves.h | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/vpr/src/draw/manual_moves.cpp b/vpr/src/draw/manual_moves.cpp index b112d998377..65b752fb56c 100644 --- a/vpr/src/draw/manual_moves.cpp +++ b/vpr/src/draw/manual_moves.cpp @@ -306,11 +306,10 @@ e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_boundin } e_create_move manual_move_display_and_propose(ManualMoveGenerator& manual_move_generator, t_pl_blocks_to_be_moved& blocks_affected, e_move_type& move_type, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities) { - draw_manual_moves_window(""); - update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); - move_type = e_move_type::MANUAL_MOVE; - return manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); + draw_manual_moves_window(""); + update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr); + move_type = e_move_type::MANUAL_MOVE; + return manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities); } - #endif /*NO_GRAPHICS*/ diff --git a/vpr/src/draw/manual_moves.h b/vpr/src/draw/manual_moves.h index b10edc9cdbe..d364dd1882a 100644 --- a/vpr/src/draw/manual_moves.h +++ b/vpr/src/draw/manual_moves.h @@ -155,7 +155,6 @@ e_move_result pl_do_manual_move(double d_cost, double d_timing, double d_boundin e_create_move manual_move_display_and_propose(ManualMoveGenerator& manual_move_generator, t_pl_blocks_to_be_moved& blocks_affected, e_move_type& move_type, float rlim, const t_placer_opts& placer_opts, const PlacerCriticalities* criticalities); - #endif /*NO_GRAPHICS*/ #endif /* MANUAL_MOVES_H */