diff --git a/doc/src/api/vprinternals/draw_files.rst b/doc/src/api/vprinternals/draw_files.rst
index 218c45de141..df1ae2d5ba3 100644
--- a/doc/src/api/vprinternals/draw_files.rst
+++ b/doc/src/api/vprinternals/draw_files.rst
@@ -31,6 +31,12 @@ draw_global.h/cpp
.. doxygenfile:: draw_global.h
:project: vpr
:sections: detaileddescription
+
+draw_floorplanning.h/cpp
+--------------
+.. doxygenfile:: draw_floorplanning.h
+ :project: vpr
+ :sections: detaileddescription
draw_mux.h/cpp
--------------
@@ -120,4 +126,4 @@ ui_setup.h/cpp
--------------
.. doxygenfile:: ui_setup.h
:project: vpr
- :sections: detaileddescription
\ No newline at end of file
+ :sections: detaileddescription
diff --git a/vpr/main.ui b/vpr/main.ui
index d6b4b31e079..21f78e1604f 100644
--- a/vpr/main.ui
+++ b/vpr/main.ui
@@ -164,6 +164,21 @@
9
+
+
+
+ False
+ True
+ 8
+
+
diff --git a/vpr/src/base/partition_region.cpp b/vpr/src/base/partition_region.cpp
index d06bfa37240..4e08d58f79c 100644
--- a/vpr/src/base/partition_region.cpp
+++ b/vpr/src/base/partition_region.cpp
@@ -9,6 +9,10 @@ std::vector PartitionRegion::get_partition_region() {
return partition_region;
}
+std::vector PartitionRegion::get_partition_region() const {
+ return partition_region;
+}
+
void PartitionRegion::set_partition_region(std::vector pr) {
partition_region = pr;
}
diff --git a/vpr/src/base/partition_region.h b/vpr/src/base/partition_region.h
index 799a530cbdc..eb89399191c 100644
--- a/vpr/src/base/partition_region.h
+++ b/vpr/src/base/partition_region.h
@@ -26,6 +26,7 @@ class PartitionRegion {
* @brief Return the union of regions
*/
std::vector get_partition_region();
+ std::vector get_partition_region() const;
/**
* @brief Set the union of regions
diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp
index b17da51cb22..1e371356b4b 100644
--- a/vpr/src/draw/draw.cpp
+++ b/vpr/src/draw/draw.cpp
@@ -57,6 +57,7 @@
#include "breakpoint.h"
#include "manual_moves.h"
#include "draw_noc.h"
+#include "draw_floorplanning.h"
#include "move_utils.h"
#include "ui_setup.h"
@@ -126,6 +127,7 @@ 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 set_draw_partitions(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);
@@ -256,6 +258,11 @@ static void draw_main_canvas(ezgl::renderer* g) {
draw_noc(g);
+ if (draw_state->draw_partitions) {
+ highlight_regions(g);
+ draw_constrained_atoms(g);
+ }
+
if (draw_state->color_map) {
draw_color_map_legend(*draw_state->color_map, g);
draw_state->color_map.reset(); //Free color map in preparation for next redraw
@@ -1098,6 +1105,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);
+
+ // Connect Draw Partitions Checkbox
+ GObject* draw_partitions = app->get_object("drawPartitions");
+ g_signal_connect(draw_partitions, "toggled", G_CALLBACK(set_draw_partitions), app);
}
// Callback function for Block Outline checkbox
@@ -1144,6 +1155,21 @@ static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer
application.refresh_drawing();
}
+// Callback function for Draw Partitions checkbox
+static void set_draw_partitions(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) {
+ t_draw_state* draw_state = get_draw_state_vars();
+
+ // assign corresponding bool value to draw_state->draw_partitions
+ if (gtk_toggle_button_get_active((GtkToggleButton*)widget))
+ draw_state->draw_partitions = true;
+ else
+ draw_state->draw_partitions = false;
+
+ //redraw
+ application.update_message(draw_state->default_message);
+ application.refresh_drawing();
+}
+
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_floorplanning.cpp b/vpr/src/draw/draw_floorplanning.cpp
new file mode 100644
index 00000000000..0e421a0b0f9
--- /dev/null
+++ b/vpr/src/draw/draw_floorplanning.cpp
@@ -0,0 +1,232 @@
+#include
+
+#include "vpr_utils.h"
+#include "vpr_error.h"
+
+#include "globals.h"
+#include "atom_netlist.h"
+#include "draw_floorplanning.h"
+#include "vpr_constraints.h"
+#include "draw_color.h"
+#include "draw.h"
+#include "draw_rr.h"
+#include "draw_rr_edges.h"
+#include "draw_basic.h"
+#include "draw_toggle_functions.h"
+#include "draw_triangle.h"
+#include "draw_searchbar.h"
+#include "draw_mux.h"
+#include "read_xml_arch_file.h"
+#include "draw_global.h"
+#include "intra_logic_block.h"
+#include "move_utils.h"
+#include "route_export.h"
+#include "tatum/report/TimingPathCollector.hpp"
+
+#ifdef VTR_ENABLE_DEBUG_LOGGING
+# include "move_utils.h"
+#endif
+
+#ifdef WIN32 /* For runtime tracking in WIN32. The clock() function defined in time.h will *
+ * track CPU runtime. */
+# include
+#else /* For X11. The clock() function in time.h will not output correct time difference *
+ * for X11, because the graphics is processed by the Xserver rather than local CPU, *
+ * which means tracking CPU time will not be the same as the actual wall clock time. *
+ * Thus, so use gettimeofday() in sys/time.h to track actual calendar time. */
+# include
+#endif
+
+#ifndef NO_GRAPHICS
+
+//To process key presses we need the X11 keysym definitions,
+//which are unavailable when building with MINGW
+# if defined(X11) && !defined(__MINGW32__)
+# include
+# endif
+
+static void draw_internal_pb(const ClusterBlockId clb_index, t_pb* current_pb, const t_pb* pb_to_draw, const ezgl::rectangle& parent_bbox, const t_logical_block_type_ptr type, ezgl::color color, ezgl::renderer* g);
+
+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: hard to differentiate between outline & primitive.
+ 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
+};
+
+/* Highlights partitions. */
+void highlight_regions(ezgl::renderer* g) {
+ auto& floorplanning_ctx = g_vpr_ctx.floorplanning();
+ auto constraints = floorplanning_ctx.constraints;
+ auto num_partitions = constraints.get_num_partitions();
+ t_draw_coords* draw_coords = get_draw_coords_vars();
+
+ for (int partitionID = 0; partitionID < num_partitions; partitionID++) {
+ auto partition = constraints.get_partition((PartitionId)partitionID);
+ auto& partition_region = partition.get_part_region();
+ auto regions = partition_region.get_partition_region();
+
+ bool name_drawn = false;
+ ezgl::color partition_color = kelly_max_contrast_colors[partitionID % (kelly_max_contrast_colors.size())];
+ g->set_color(partition_color, 30);
+
+ // The units of space in the constraints xml file will be refered to as "tile units"
+ // The units of space that'll be used by ezgl to draw will be refered to as "on screen units"
+
+ // Find the coordinates of the region by retrieving from the xml file
+ // which tiles are at the corner of the region, then translate that to on
+ // the on screen units for ezgl to use.
+
+ for (int region = 0; (size_t)region < regions.size(); region++) {
+ auto tile_rect = regions[region].get_region_rect();
+
+ ezgl::rectangle top_right = draw_coords->get_absolute_clb_bbox(tile_rect.xmax(),
+ tile_rect.ymax(), 0);
+ ezgl::rectangle bottom_left = draw_coords->get_absolute_clb_bbox(tile_rect.xmin(),
+ tile_rect.ymin(), 0);
+
+ ezgl::rectangle on_screen_rect(bottom_left.bottom_left(), top_right.top_right());
+
+ // Ensures name is drawn only once per partition
+ if (!name_drawn) {
+ g->set_font_size(10);
+ std::string partition_name = partition.get_name();
+
+ g->set_color(partition_color, 230);
+
+ g->draw_text(
+ on_screen_rect.center(),
+ partition_name.c_str(),
+ on_screen_rect.width() - 10,
+ on_screen_rect.height() - 10);
+
+ name_drawn = true;
+
+ g->set_color(partition_color, 30);
+ }
+
+ g->fill_rectangle(on_screen_rect);
+ }
+ }
+}
+
+/* Function to draw all constrained primitives */
+void draw_constrained_atoms(ezgl::renderer* g) {
+ auto& floorplanning_ctx = g_vpr_ctx.floorplanning();
+ auto constraints = floorplanning_ctx.constraints;
+ auto num_partitions = constraints.get_num_partitions();
+ auto& atom_ctx = g_vpr_ctx.atom();
+ auto& cluster_ctx = g_vpr_ctx.clustering();
+
+ for (int partitionID = 0; partitionID < num_partitions; partitionID++) {
+ auto atoms = constraints.get_part_atoms((PartitionId)partitionID);
+
+ //iterate through every primitive in the partition
+ for (size_t j = 0; j < atoms.size(); j++) {
+ AtomBlockId const& const_atom = atoms[j];
+ if (atom_ctx.lookup.atom_pb(const_atom) != nullptr) {
+ const t_pb* pb = atom_ctx.lookup.atom_pb(const_atom);
+ auto color = kelly_max_contrast_colors[partitionID % (kelly_max_contrast_colors.size())];
+ ClusterBlockId clb_index = atom_ctx.lookup.atom_clb(atoms[j]);
+ auto type = cluster_ctx.clb_nlist.block_type(clb_index);
+
+ draw_internal_pb(clb_index, cluster_ctx.clb_nlist.block_pb(clb_index), pb, ezgl::rectangle({0, 0}, 0, 0), type, color, g);
+ }
+ }
+ }
+}
+
+/* Helper subroutine to draw a specific subblock (pb_to_draw). This function traverses through the pb_graph
+ * which a netlist block can map to, and checks each sub-block inside its parent blocks
+ * to see if it is the sub-block to be drawn.
+ */
+static void draw_internal_pb(const ClusterBlockId clb_index, t_pb* current_pb, const t_pb* pb_to_draw, const ezgl::rectangle& parent_bbox, const t_logical_block_type_ptr type, ezgl::color color, ezgl::renderer* g) {
+ t_draw_coords* draw_coords = get_draw_coords_vars();
+ t_draw_state* draw_state = get_draw_state_vars();
+
+ t_pb_type* pb_type = current_pb->pb_graph_node->pb_type;
+ ezgl::rectangle temp = draw_coords->get_pb_bbox(clb_index, *current_pb->pb_graph_node);
+ ezgl::rectangle abs_bbox = temp + parent_bbox.bottom_left();
+
+ // if the current pb is not the pb_to_draw,
+ if (current_pb != pb_to_draw) {
+ int num_child_types = current_pb->get_num_child_types();
+ for (int i = 0; i < num_child_types; ++i) {
+ if (current_pb->child_pbs[i] == nullptr) {
+ continue;
+ }
+
+ int num_pb = current_pb->get_num_children_of_type(i);
+ for (int j = 0; j < num_pb; ++j) {
+ t_pb* child_pb = ¤t_pb->child_pbs[i][j];
+
+ VTR_ASSERT(child_pb != nullptr);
+
+ t_pb_type* pb_child_type = child_pb->pb_graph_node->pb_type;
+
+ if (pb_child_type == nullptr) {
+ continue;
+ }
+
+ // now recurse
+ draw_internal_pb(clb_index, child_pb, pb_to_draw, abs_bbox, type, color, g);
+ }
+ }
+ }
+
+ //if the current pb is the pb we want to draw
+ else {
+ //Draws the pb as a rectangle on the screen
+ g->set_color(color);
+
+ g->fill_rectangle(abs_bbox);
+ if (draw_state->draw_block_outlines) {
+ g->draw_rectangle(abs_bbox);
+ }
+
+ g->set_color(ezgl::BLACK);
+
+ //Draws the name of the pb
+ if (current_pb->name != nullptr) {
+ g->set_font_size(10);
+
+ std::string pb_type_name(pb_type->name);
+ std::string pb_name(current_pb->name);
+
+ std::string blk_tag = pb_name + " (" + pb_type_name + ")";
+
+ g->draw_text(
+ abs_bbox.center(),
+ blk_tag.c_str(),
+ abs_bbox.width() + 10,
+ abs_bbox.height() + 10);
+
+ } else {
+ g->draw_text(
+ abs_bbox.center(),
+ pb_type->name,
+ abs_bbox.width() + 10,
+ abs_bbox.height() + 10);
+ }
+ }
+}
+
+#endif
diff --git a/vpr/src/draw/draw_floorplanning.h b/vpr/src/draw/draw_floorplanning.h
new file mode 100644
index 00000000000..36b0dcd2318
--- /dev/null
+++ b/vpr/src/draw/draw_floorplanning.h
@@ -0,0 +1,28 @@
+/**
+ * @file draw_floorplanning.h
+ *
+ * draw_floorplanning.cpp contains all the functions pertaining to drawing
+ * floorplanning constraints provided to VPR by the user.
+ */
+#ifndef DRAW_FLOORPLANNING_H
+#define DRAW_FLOORPLANNING_H
+
+#include "globals.h"
+
+#ifndef NO_GRAPHICS
+
+# include "draw_global.h"
+
+# include "ezgl/point.hpp"
+# include "ezgl/application.hpp"
+# include "ezgl/graphics.hpp"
+
+/* Highlights partitions. */
+void highlight_regions(ezgl::renderer* g);
+
+/* Function to draw all constrained primitives */
+void draw_constrained_atoms(ezgl::renderer* g);
+
+#endif /*NO_GRAPHICS*/
+
+#endif /*DRAW_FLOORPLANNING_H*/
diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h
index 14a33be199b..ac3a5f557b8 100644
--- a/vpr/src/draw/draw_types.h
+++ b/vpr/src/draw/draw_types.h
@@ -196,6 +196,9 @@ struct t_draw_state {
///@brief Boolean that toggles block names
bool draw_block_text = true;
+ ///@brief Boolean that turns on drawing partitions
+ bool draw_partitions = false;
+
///@brief integer value for net max fanout
int draw_net_max_fanout = std::numeric_limits::max();