diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 717ba35ed90..a05c525ec01 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -94,6 +94,7 @@ void SetupVPR(const t_options* Options, FileNameOpts->CmosTechFile = Options->CmosTechFile; FileNameOpts->out_file_prefix = Options->out_file_prefix; FileNameOpts->read_vpr_constraints_file = Options->read_vpr_constraints_file; + FileNameOpts->write_vpr_constraints_file = Options->write_vpr_constraints_file; FileNameOpts->verify_file_digests = Options->verify_file_digests; @@ -585,6 +586,8 @@ static void SetupPlacerOpts(const t_options& Options, t_placer_opts* PlacerOpts) PlacerOpts->place_reward_fun = Options.place_reward_fun; PlacerOpts->place_crit_limit = Options.place_crit_limit; PlacerOpts->place_agent_algorithm = Options.place_agent_algorithm; + PlacerOpts->place_constraint_expand = Options.place_constraint_expand; + PlacerOpts->place_constraint_subtile = Options.place_constraint_subtile; } static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysis_opts) { diff --git a/vpr/src/base/clustered_netlist_utils.cpp b/vpr/src/base/clustered_netlist_utils.cpp index dc70316cad2..a7488d9ba89 100644 --- a/vpr/src/base/clustered_netlist_utils.cpp +++ b/vpr/src/base/clustered_netlist_utils.cpp @@ -1,4 +1,5 @@ #include "clustered_netlist_utils.h" +#include "globals.h" ClusteredPinAtomPinsLookup::ClusteredPinAtomPinsLookup(const ClusteredNetlist& clustered_netlist, const AtomNetlist& atom_netlist, const IntraLbPbPinLookup& pb_gpin_lookup) { init_lookup(clustered_netlist, atom_netlist, pb_gpin_lookup); } @@ -33,3 +34,25 @@ void ClusteredPinAtomPinsLookup::init_lookup(const ClusteredNetlist& clustered_n } } } + +ClusterAtomsLookup::ClusterAtomsLookup() { + init_lookup(); +} + +void ClusterAtomsLookup::init_lookup() { + auto& atom_ctx = g_vpr_ctx.atom(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + + cluster_atoms.resize(cluster_ctx.clb_nlist.blocks().size()); + + for (auto atom_blk_id : atom_ctx.nlist.blocks()) { + ClusterBlockId clb_index = atom_ctx.lookup.atom_clb(atom_blk_id); + + cluster_atoms[clb_index].push_back(atom_blk_id); + } +} + +std::vector ClusterAtomsLookup::atoms_in_cluster(ClusterBlockId blk_id) { + std::vector atoms = cluster_atoms[blk_id]; + return atoms; +} diff --git a/vpr/src/base/clustered_netlist_utils.h b/vpr/src/base/clustered_netlist_utils.h index fcb1ddb1115..3568120e2fc 100644 --- a/vpr/src/base/clustered_netlist_utils.h +++ b/vpr/src/base/clustered_netlist_utils.h @@ -27,4 +27,22 @@ class ClusteredPinAtomPinsLookup { vtr::vector atom_pin_connected_cluster_pin_; }; +/* + * This lookup is used to see which atoms are in each cluster block. + * Getting the atoms inside of a cluster is an order k lookup. + * The data is initialized automatically upon creation of the object. + * The class should only be used after the clustered netlist is created. + */ +class ClusterAtomsLookup { + public: + ClusterAtomsLookup(); + std::vector atoms_in_cluster(ClusterBlockId blk_id); + + private: + void init_lookup(); + + private: + //Store the atom ids of the atoms inside each cluster + vtr::vector> cluster_atoms; +}; #endif diff --git a/vpr/src/base/gen/vpr_constraints_uxsdcxx.h b/vpr/src/base/gen/vpr_constraints_uxsdcxx.h index 86786e69584..f2cd1bf64c4 100644 --- a/vpr/src/base/gen/vpr_constraints_uxsdcxx.h +++ b/vpr/src/base/gen/vpr_constraints_uxsdcxx.h @@ -25,6 +25,10 @@ #include "pugixml.hpp" #include "vpr_constraints_uxsdcxx_interface.h" + +//sentinel value for indicating that a subtile has not been specified +constexpr int NO_SUBTILE = -1; + /* All uxsdcxx functions and structs live in this namespace. */ namespace uxsd { @@ -730,7 +734,7 @@ inline void write_partition(T& in, std::ostream& os, Context& context) { for (size_t i = 0, n = in.num_partition_add_region(context); i < n; i++) { auto child_context = in.get_partition_add_region(i, context); os << "(args.place_constraint_subtile, "--place_constraint_subtile") + .help( + "The bool used to say whether to print subtile constraints when printing a floorplan constraints XML file." + "If it is off, no subtile locations are specified when printing the floorplan constraints." + "If it is on, the floorplan constraints are printed with the subtiles from current placement.") + .default_value("off") + .show_in(argparse::ShowIn::HELP_ONLY); + /* * place_grp.add_argument(args.place_timing_cost_func, "--place_timing_cost_func") * .help( diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index aa4e30377f1..c8144b81ea2 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -27,6 +27,7 @@ struct t_options { argparse::ArgValue write_rr_graph_file; argparse::ArgValue read_rr_graph_file; argparse::ArgValue read_vpr_constraints_file; + argparse::ArgValue write_vpr_constraints_file; argparse::ArgValue write_placement_delay_lookup; argparse::ArgValue read_placement_delay_lookup; @@ -128,6 +129,8 @@ struct t_options { argparse::ArgValue place_reward_fun; //argparse::ArgValue place_timing_cost_func; argparse::ArgValue place_crit_limit; + argparse::ArgValue place_constraint_expand; + argparse::ArgValue place_constraint_subtile; /* Timing-driven placement options only */ argparse::ArgValue PlaceTimingTradeoff; diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 7b4f2df1c24..ea5bd64e689 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -69,7 +69,7 @@ #include "cluster.h" #include "output_clustering.h" #include "vpr_constraints_reader.h" - +#include "vpr_constraints_writer.h" #include "pack_report.h" #include "overuse_report.h" @@ -617,6 +617,7 @@ void vpr_load_packing(t_vpr_setup& vpr_setup, const t_arch& arch) { bool vpr_place_flow(t_vpr_setup& vpr_setup, const t_arch& arch) { VTR_LOG("\n"); const auto& placer_opts = vpr_setup.PlacerOpts; + const auto& filename_opts = vpr_setup.FileNameOpts; if (placer_opts.doPlacement == STAGE_SKIP) { //pass } else { @@ -635,6 +636,11 @@ bool vpr_place_flow(t_vpr_setup& vpr_setup, const t_arch& arch) { post_place_sync(); } + //Write out a vpr floorplanning constraints file if the option is specified + if (!filename_opts.write_vpr_constraints_file.empty()) { + write_vpr_floorplan_constraints(filename_opts.write_vpr_constraints_file.c_str(), placer_opts.place_constraint_expand, placer_opts.place_constraint_subtile); + } + return true; } diff --git a/vpr/src/base/vpr_constraints_serializer.h b/vpr/src/base/vpr_constraints_serializer.h index c87449f4db7..4007b7c5c3b 100644 --- a/vpr/src/base/vpr_constraints_serializer.h +++ b/vpr/src/base/vpr_constraints_serializer.h @@ -50,10 +50,24 @@ * For more detail on how the load and write interfaces work with uxsdcxx, refer to 'vpr/src/route/SCHEMA_GENERATOR.md' */ +/* + * Used for the PartitionReadContext, which is used when writing out a constraints XML file. + * Groups together the information needed when printing a partition. + */ +struct partition_info { + Partition part; + std::vector atoms; + PartitionId part_id; +}; + +/* + * The contexts that end with "ReadContext" are used when writing out the XML file. + * The contexts that end with "WriteContext" are used when reading in the XML file. + */ struct VprConstraintsContextTypes : public uxsd::DefaultVprConstraintsContextTypes { - using AddAtomReadContext = void*; - using AddRegionReadContext = void*; - using PartitionReadContext = void*; + using AddAtomReadContext = AtomBlockId; + using AddRegionReadContext = Region; + using PartitionReadContext = partition_info; using PartitionListReadContext = void*; using VprConstraintsReadContext = void*; using AddAtomWriteContext = void*; @@ -65,6 +79,12 @@ struct VprConstraintsContextTypes : public uxsd::DefaultVprConstraintsContextTyp class VprConstraintsSerializer final : public uxsd::VprConstraintsBase { public: + VprConstraintsSerializer() + : report_error_(nullptr) {} + VprConstraintsSerializer(VprConstraints constraints) + : constraints_(constraints) + , report_error_(nullptr) {} + void start_load(const std::function* report_error_in) final { // report_error_in should be invoked if VprConstraintsSerializer encounters // an error during the read. @@ -89,8 +109,10 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase * */ - virtual inline const char* get_add_atom_name_pattern(void*& /*ctx*/) final { - return temp_.c_str(); + virtual inline const char* get_add_atom_name_pattern(AtomBlockId& blk_id) final { + auto& atom_ctx = g_vpr_ctx.atom(); + temp_atom_string_ = atom_ctx.nlist.block_name(blk_id); + return temp_atom_string_.c_str(); } virtual inline void set_add_atom_name_pattern(const char* name_pattern, void*& /*ctx*/) final { @@ -141,33 +163,32 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase * */ - virtual inline int get_add_region_subtile(void*& /*ctx*/) final { - int i = 0; - return i; + virtual inline int get_add_region_subtile(Region& r) final { + return r.get_sub_tile(); } virtual inline void set_add_region_subtile(int subtile, void*& /*ctx*/) final { loaded_region.set_sub_tile(subtile); } - virtual inline int get_add_region_x_high(void*& /*ctx*/) final { - int i = 0; - return i; + virtual inline int get_add_region_x_high(Region& r) final { + vtr::Rect rect = r.get_region_rect(); + return rect.xmax(); } - virtual inline int get_add_region_x_low(void*& /*ctx*/) final { - int i = 0; - return i; + virtual inline int get_add_region_x_low(Region& r) final { + vtr::Rect rect = r.get_region_rect(); + return rect.xmin(); } - virtual inline int get_add_region_y_high(void*& /*ctx*/) final { - int i = 0; - return i; + virtual inline int get_add_region_y_high(Region& r) final { + vtr::Rect rect = r.get_region_rect(); + return rect.ymax(); } - virtual inline int get_add_region_y_low(void*& /*ctx*/) final { - int i = 0; - return i; + virtual inline int get_add_region_y_low(Region& r) final { + vtr::Rect rect = r.get_region_rect(); + return rect.ymin(); } /** Generated for complex type "partition": @@ -179,8 +200,9 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase * */ - virtual inline const char* get_partition_name(void*& /*ctx*/) final { - return temp_.c_str(); + virtual inline const char* get_partition_name(partition_info& part_info) final { + temp_part_string_ = part_info.part.get_name(); + return temp_part_string_.c_str(); } virtual inline void set_partition_name(const char* name, void*& /*ctx*/) final { loaded_partition.set_name(name); @@ -200,12 +222,11 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase regions = pr.get_partition_region(); + return regions.size(); } - virtual inline void* get_partition_add_region(int /*n*/, void*& /*ctx*/) final { - return nullptr; + virtual inline Region get_partition_add_region(int n, partition_info& part_info) final { + PartitionRegion pr = part_info.part.get_part_region(); + std::vector regions = pr.get_partition_region(); + return regions[n]; } /** Generated for complex type "partition_list": @@ -256,12 +280,24 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase atoms = constraints_.get_part_atoms(partid); + + partition_info part_info; + part_info.part = part; + part_info.part_id = partid; + part_info.atoms = atoms; + + return part_info; } /** Generated for complex type "vpr_constraints": @@ -297,17 +333,26 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase* report_error_; //temp data structures to be loaded during file reading Region loaded_region; Partition loaded_partition; PartitionRegion loaded_part_region; - VprConstraints constraints_; //temp string used when a method must return a const char* - std::string temp_; + std::string temp_ = "vpr"; //used to count the number of partitions read in from the file int num_partitions_ = 0; diff --git a/vpr/src/base/vpr_constraints_writer.cpp b/vpr/src/base/vpr_constraints_writer.cpp new file mode 100644 index 00000000000..acfc281786f --- /dev/null +++ b/vpr/src/base/vpr_constraints_writer.cpp @@ -0,0 +1,85 @@ +/* + * vpr_constraints_writer.cpp + * + * Author: khalid88 + */ + +#include "vpr_constraints_serializer.h" +#include "vpr_constraints_uxsdcxx.h" + +#include "vtr_time.h" + +#include "globals.h" +#include "pugixml.hpp" +#include "pugixml_util.hpp" +#include "echo_files.h" +#include "clustered_netlist_utils.h" + +#include +#include "vpr_constraints_writer.h" + +void write_vpr_floorplan_constraints(const char* file_name, int expand, bool subtile) { + //Fill in the constraints object to be printed out. + VprConstraints constraints; + + setup_vpr_floorplan_constraints(constraints, expand, subtile); + + VprConstraintsSerializer writer(constraints); + + if (vtr::check_file_name_extension(file_name, ".xml")) { + std::fstream fp; + fp.open(file_name, std::fstream::out | std::fstream::trunc); + fp.precision(std::numeric_limits::max_digits10); + void* context; + uxsd::write_vpr_constraints_xml(writer, context, fp); + } else { + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, + "Unknown extension on output %s", + file_name); + } +} + +void setup_vpr_floorplan_constraints(VprConstraints& constraints, int expand, bool subtile) { + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + ClusterAtomsLookup atoms_lookup; + + int part_id = 0; + /* + * For each cluster block, create a partition filled with the atoms that are currently in the cluster. + * The PartitionRegion will be the location of the block in current placement, modified by the expansion factor. + * The subtile can also optionally be set in the PartitionRegion, based on the value passed in by the user. + */ + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + std::string part_name; + part_name = cluster_ctx.clb_nlist.block_name(blk_id); + PartitionId partid(part_id); + + Partition part; + part.set_name(part_name); + + PartitionRegion pr; + Region reg; + + auto loc = place_ctx.block_locs[blk_id].loc; + + reg.set_region_rect(loc.x - expand, loc.y - expand, loc.x + expand, loc.y + expand); + if (subtile) { + int st = loc.sub_tile; + reg.set_sub_tile(st); + } + + pr.add_to_part_region(reg); + part.set_part_region(pr); + constraints.add_partition(part); + + std::vector atoms = atoms_lookup.atoms_in_cluster(blk_id); + int num_atoms = atoms.size(); + + for (auto atm = 0; atm < num_atoms; atm++) { + AtomBlockId atom_id = atoms[atm]; + constraints.add_constrained_atom(atom_id, partid); + } + part_id++; + } +} diff --git a/vpr/src/base/vpr_constraints_writer.h b/vpr/src/base/vpr_constraints_writer.h new file mode 100644 index 00000000000..8b56ee041ef --- /dev/null +++ b/vpr/src/base/vpr_constraints_writer.h @@ -0,0 +1,33 @@ +/** + * @file + * @brief This file contains functions related to writing out a vpr constraints XML file. + * + * Overview + * ======== + * VPR floorplan constraints consist of region constraints specified for primitives that must be respected during packing and placement. + * The constraints XML file is printed using the XML schema vpr/src/base/vpr_constraints.xsd + * + * Routines related to writing out the file are in vpr/src/base/vpr_constraints_serializer.h. For more information on how + * the writing interface works, refer to vpr/src/route/SCHEMA_GENERATOR.md + * + * + */ + +#ifndef VPR_SRC_BASE_VPR_CONSTRAINTS_WRITER_H_ +#define VPR_SRC_BASE_VPR_CONSTRAINTS_WRITER_H_ + +/** + * @brief Write out floorplan constraints to an XML file based on current placement + * + * @param file_name The name of the file that the constraints will be written to + * @param expand The amount the floorplan region will be expanded around the current + * x, y location of the block. Ex. if location is (1, 1) and expand = 1, + * the floorplan region will be from (0, 0) to (2, 2). + * @param subtile Specifies whether to write out the constraint regions with or without + * subtile values. + */ +void write_vpr_floorplan_constraints(const char* file_name, int expand, bool subtile); + +void setup_vpr_floorplan_constraints(VprConstraints& constraints, int expand, bool subtile); + +#endif /* VPR_SRC_BASE_VPR_CONSTRAINTS_WRITER_H_ */ diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index b09a0de34e7..38313431d49 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -753,6 +753,7 @@ struct t_file_name_opts { std::string CmosTechFile; std::string out_file_prefix; std::string read_vpr_constraints_file; + std::string write_vpr_constraints_file; bool verify_file_digests; }; @@ -1013,6 +1014,13 @@ enum class e_place_delta_delay_algorithm { * @param doPlacement * True if placement is supposed to be done in the CAD flow. * False if otherwise. + * @param place_constraint_expand + * Integer value that specifies how far to expand the floorplan + * region when printing out floorplan constraints based on + * current placement. + * @param place_constraint_subtile + * True if subtiles should be specified when printing floorplan + * constraints. False if not. */ struct t_placer_opts { t_place_algorithm place_algorithm; @@ -1064,6 +1072,8 @@ struct t_placer_opts { //int place_timing_cost_func; std::string place_reward_fun; float place_crit_limit; + int place_constraint_expand; + bool place_constraint_subtile; /** * @brief Tile types that should be used during delay sampling. diff --git a/vpr/src/place/centroid_move_generator.cpp b/vpr/src/place/centroid_move_generator.cpp index 623fe71d4c3..9a1b665941f 100644 --- a/vpr/src/place/centroid_move_generator.cpp +++ b/vpr/src/place/centroid_move_generator.cpp @@ -2,6 +2,7 @@ #include "vpr_types.h" #include "globals.h" #include "directed_moves_util.h" +#include "place_constraints.h" e_create_move CentroidMoveGenerator::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*/) { /* Pick a random block to be swapped with another random block. */ @@ -35,5 +36,12 @@ e_create_move CentroidMoveGenerator::propose_move(t_pl_blocks_to_be_moved& block return e_create_move::ABORT; } - return ::create_move(blocks_affected, b_from, to); + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + + //Check that all of the blocks affected by the move would still be in a legal floorplan region after the swap + if (!floorplan_legal(blocks_affected)) { + return e_create_move::ABORT; + } + + return create_move; } diff --git a/vpr/src/place/critical_uniform_move_generator.cpp b/vpr/src/place/critical_uniform_move_generator.cpp index 733354649b1..15d7867c6bb 100644 --- a/vpr/src/place/critical_uniform_move_generator.cpp +++ b/vpr/src/place/critical_uniform_move_generator.cpp @@ -1,5 +1,6 @@ #include "critical_uniform_move_generator.h" #include "globals.h" +#include "place_constraints.h" e_create_move CriticalUniformMoveGenerator::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*/) { auto& place_ctx = g_vpr_ctx.placement(); @@ -33,5 +34,12 @@ e_create_move CriticalUniformMoveGenerator::propose_move(t_pl_blocks_to_be_moved return e_create_move::ABORT; } - return ::create_move(blocks_affected, b_from, to); + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + + //Check that all of the blocks affected by the move would still be in a legal floorplan region after the swap + if (!floorplan_legal(blocks_affected)) { + return e_create_move::ABORT; + } + + return create_move; } diff --git a/vpr/src/place/feasible_region_move_generator.cpp b/vpr/src/place/feasible_region_move_generator.cpp index 1ab6e8770aa..2d075b9a4e2 100644 --- a/vpr/src/place/feasible_region_move_generator.cpp +++ b/vpr/src/place/feasible_region_move_generator.cpp @@ -2,6 +2,7 @@ #include "globals.h" #include #include "math.h" +#include "place_constraints.h" e_create_move FeasibleRegionMoveGenerator::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) { auto& place_ctx = g_vpr_ctx.placement(); @@ -122,5 +123,12 @@ e_create_move FeasibleRegionMoveGenerator::propose_move(t_pl_blocks_to_be_moved& return e_create_move::ABORT; } - return ::create_move(blocks_affected, b_from, to); + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + + //Check that all of the blocks affected by the move would still be in a legal floorplan region after the swap + if (!floorplan_legal(blocks_affected)) { + return e_create_move::ABORT; + } + + return create_move; } diff --git a/vpr/src/place/initial_placement.cpp b/vpr/src/place/initial_placement.cpp index 4538dcb6604..45784d6e698 100644 --- a/vpr/src/place/initial_placement.cpp +++ b/vpr/src/place/initial_placement.cpp @@ -98,10 +98,8 @@ static int check_macro_can_be_placed(t_pl_macro pl_macro, int itype, t_pl_loc he bool member_loc_good = macro_pr.is_loc_in_part_reg(member_pos); if (!member_loc_good) { macro_can_be_placed = false; - VTR_LOG("Block member %zu did not pass the macro constraints check with location x: %d y: %d subtile %d\n", pl_macro.members[imember].blk_index, member_pos.x, member_pos.y, member_pos.sub_tile); break; } - VTR_LOG("Block member %zu passed the macro constraints check with location x: %d y: %d subtile %d\n", pl_macro.members[imember].blk_index, member_pos.x, member_pos.y, member_pos.sub_tile); } // Check whether the location could accept block of this type @@ -304,7 +302,7 @@ static void initial_placement_blocks(std::vector>& free_locatio // Make sure that the position is EMPTY_BLOCK before placing the block down VTR_ASSERT(place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile] == EMPTY_BLOCK_ID); - bool floorplan_good = cluster_floorplanning_check(blk_id, to); + bool floorplan_good = cluster_floorplanning_legal(blk_id, to); if (floorplan_good) { place_ctx.grid_blocks[to.x][to.y].blocks[to.sub_tile] = blk_id; diff --git a/vpr/src/place/median_move_generator.cpp b/vpr/src/place/median_move_generator.cpp index fb7a0a2589e..1d1f3335268 100644 --- a/vpr/src/place/median_move_generator.cpp +++ b/vpr/src/place/median_move_generator.cpp @@ -1,7 +1,7 @@ #include "median_move_generator.h" #include "globals.h" #include - +#include "place_constraints.h" #include "placer_globals.h" static bool get_bb_incrementally(ClusterNetId net_id, t_bb* bb_coord_new, int xold, int yold, int xnew, int ynew); @@ -122,7 +122,14 @@ e_create_move MedianMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks_ if (!find_to_loc_centroid(cluster_from_type, from, median_point, range_limiters, to)) return e_create_move::ABORT; - return ::create_move(blocks_affected, b_from, to); + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + + //Check that all of the blocks affected by the move would still be in a legal floorplan region after the swap + if (!floorplan_legal(blocks_affected)) { + return e_create_move::ABORT; + } + + return create_move; } /* Finds the bounding box of a net and stores its coordinates in the * diff --git a/vpr/src/place/move_transactions.h b/vpr/src/place/move_transactions.h index 0856aea97a0..47e06ba808a 100644 --- a/vpr/src/place/move_transactions.h +++ b/vpr/src/place/move_transactions.h @@ -6,10 +6,8 @@ /* Stores the information of the move for a block that is * * moved during placement * * block_num: the index of the moved block * - * xold: the x_coord that the block is moved from * - * xnew: the x_coord that the block is moved to * - * yold: the y_coord that the block is moved from * - * xnew: the x_coord that the block is moved to */ + * old_loc: the location the block is moved from * + * new_loc: the location the block is moved to */ struct t_pl_moved_block { ClusterBlockId block_num; t_pl_loc old_loc; @@ -26,7 +24,7 @@ struct t_pl_moved_block { * swapping two blocks. * * moved blocks: a list of moved blocks data structure with * * information on the move. * - * [0...num_moved_blocks-1] * + * [0...max_blocks-1] * * affected_pins: pins affected by this move (used to * * incrementally invalidate parts of the timing * * graph. */ diff --git a/vpr/src/place/place_constraints.cpp b/vpr/src/place/place_constraints.cpp index 27c83b20009..0b4da8eb26c 100644 --- a/vpr/src/place/place_constraints.cpp +++ b/vpr/src/place/place_constraints.cpp @@ -18,8 +18,8 @@ int check_placement_floorplanning() { auto& place_ctx = g_vpr_ctx.placement(); for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { - auto& loc = place_ctx.block_locs[blk_id].loc; - if (!cluster_floorplanning_check(blk_id, loc)) { + auto loc = place_ctx.block_locs[blk_id].loc; + if (!cluster_floorplanning_legal(blk_id, loc)) { error++; VTR_LOG_ERROR("Block %zu is not in correct floorplanning region.\n", size_t(blk_id)); } @@ -36,7 +36,7 @@ bool is_cluster_constrained(ClusterBlockId blk_id) { return (!pr.empty()); } -bool is_macro_constrained(t_pl_macro pl_macro) { +bool is_macro_constrained(const t_pl_macro& pl_macro) { bool is_macro_constrained = false; bool is_member_constrained = false; @@ -54,7 +54,7 @@ bool is_macro_constrained(t_pl_macro pl_macro) { } /*Returns PartitionRegion of where the head of the macro could go*/ -PartitionRegion constrained_macro_locs(t_pl_macro pl_macro) { +PartitionRegion constrained_macro_locs(const t_pl_macro& pl_macro) { PartitionRegion macro_pr; bool is_member_constrained = false; int num_constrained_members = 0; @@ -114,7 +114,7 @@ PartitionRegion constrained_macro_locs(t_pl_macro pl_macro) { } /*returns true if location is compatible with floorplanning constraints, false if not*/ -bool cluster_floorplanning_check(ClusterBlockId blk_id, t_pl_loc loc) { +bool cluster_floorplanning_legal(ClusterBlockId blk_id, const t_pl_loc& loc) { auto& floorplanning_ctx = g_vpr_ctx.floorplanning(); bool floorplanning_good = false; @@ -125,8 +125,7 @@ bool cluster_floorplanning_check(ClusterBlockId blk_id, t_pl_loc loc) { //not constrained so will not have floorplanning issues floorplanning_good = true; } else { - PartitionRegion pr; - pr = floorplanning_ctx.cluster_constraints[blk_id]; + PartitionRegion pr = floorplanning_ctx.cluster_constraints[blk_id]; bool in_pr = pr.is_loc_in_part_reg(loc); //if location is in partitionregion, floorplanning is respected @@ -134,8 +133,10 @@ bool cluster_floorplanning_check(ClusterBlockId blk_id, t_pl_loc loc) { if (in_pr) { floorplanning_good = true; } else { +#ifdef VERBOSE VTR_LOG("Block %zu did not pass cluster_floorplanning_check \n", size_t(blk_id)); VTR_LOG("Loc is x: %d, y: %d, subtile: %d \n", loc.x, loc.y, loc.sub_tile); +#endif } } diff --git a/vpr/src/place/place_constraints.h b/vpr/src/place/place_constraints.h index f0beff837bf..90ea1e03be1 100644 --- a/vpr/src/place/place_constraints.h +++ b/vpr/src/place/place_constraints.h @@ -5,9 +5,10 @@ * Created on: Mar. 1, 2021 * Author: khalid88 */ +#include "move_transactions.h" #ifndef VPR_SRC_PLACE_PLACE_CONSTRAINTS_H_ -#define VPR_SRC_PLACE_PLACE_CONSTRAINTS_H_ +# define VPR_SRC_PLACE_PLACE_CONSTRAINTS_H_ /* * Check that placement of each block is within the floorplan constraint region of that block (if the block has any constraints). @@ -23,16 +24,31 @@ bool is_cluster_constrained(ClusterBlockId blk_id); /* * Check if the placement location would respect floorplan constraints of the block, if it has any */ -bool cluster_floorplanning_check(ClusterBlockId blk_id, t_pl_loc loc); +bool cluster_floorplanning_legal(ClusterBlockId blk_id, const t_pl_loc& loc); /* * Check whether any member of the macro has floorplan constraints */ -bool is_macro_constrained(t_pl_macro pl_macro); +bool is_macro_constrained(const t_pl_macro& pl_macro); /* * Returns region of valid locations for the head of the macro based on floorplan constraints */ -PartitionRegion constrained_macro_locs(t_pl_macro pl_macro); +PartitionRegion constrained_macro_locs(const t_pl_macro& pl_macro); + +inline bool floorplan_legal(const t_pl_blocks_to_be_moved& blocks_affected) { + bool floorplan_legal; + + for (int i = 0; i < blocks_affected.num_moved_blocks; i++) { + floorplan_legal = cluster_floorplanning_legal(blocks_affected.moved_blocks[i].block_num, blocks_affected.moved_blocks[i].new_loc); + if (!floorplan_legal) { +# ifdef VERBOSE + VTR_LOG("Move aborted for block %zu, location tried was x: %d, y: %d, subtile: %d \n", size_t(blocks_affected.moved_blocks[i].block_num), blocks_affected.moved_blocks[i].new_loc.x, blocks_affected.moved_blocks[i].new_loc.y, blocks_affected.moved_blocks[i].new_loc.sub_tile); +# endif + return false; + } + } + return true; +} #endif /* VPR_SRC_PLACE_PLACE_CONSTRAINTS_H_ */ diff --git a/vpr/src/place/uniform_move_generator.cpp b/vpr/src/place/uniform_move_generator.cpp index cda816e3a2b..cbb0d2c2401 100644 --- a/vpr/src/place/uniform_move_generator.cpp +++ b/vpr/src/place/uniform_move_generator.cpp @@ -1,5 +1,6 @@ #include "uniform_move_generator.h" #include "globals.h" +#include "place_constraints.h" e_create_move UniformMoveGenerator::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*/) { /* Pick a random block to be swapped with another random block. */ @@ -34,5 +35,12 @@ e_create_move UniformMoveGenerator::propose_move(t_pl_blocks_to_be_moved& blocks VTR_LOG("\n"); #endif - return ::create_move(blocks_affected, b_from, to); + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + + //Check that all of the blocks affected by the move would still be in a legal floorplan region after the swap + if (!floorplan_legal(blocks_affected)) { + return e_create_move::ABORT; + } + + return create_move; } diff --git a/vpr/src/place/weighted_centroid_move_generator.cpp b/vpr/src/place/weighted_centroid_move_generator.cpp index 0a3ae5f6245..34060f56a5d 100644 --- a/vpr/src/place/weighted_centroid_move_generator.cpp +++ b/vpr/src/place/weighted_centroid_move_generator.cpp @@ -2,6 +2,7 @@ #include "globals.h" #include #include "directed_moves_util.h" +#include "place_constraints.h" e_create_move WeightedCentroidMoveGenerator::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) { /* Pick a random block to be swapped with another random block. */ @@ -35,5 +36,12 @@ e_create_move WeightedCentroidMoveGenerator::propose_move(t_pl_blocks_to_be_move return e_create_move::ABORT; } - return ::create_move(blocks_affected, b_from, to); + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + + //Check that all of the blocks affected by the move would still be in a legal floorplan region after the swap + if (!floorplan_legal(blocks_affected)) { + return e_create_move::ABORT; + } + + return create_move; } diff --git a/vpr/src/place/weighted_median_move_generator.cpp b/vpr/src/place/weighted_median_move_generator.cpp index 5f4baded879..761c9b30c5a 100644 --- a/vpr/src/place/weighted_median_move_generator.cpp +++ b/vpr/src/place/weighted_median_move_generator.cpp @@ -2,6 +2,7 @@ #include "globals.h" #include #include "math.h" +#include "place_constraints.h" #define CRIT_MULT_FOR_W_MEDIAN 10 @@ -101,7 +102,15 @@ e_create_move WeightedMedianMoveGenerator::propose_move(t_pl_blocks_to_be_moved& if (!find_to_loc_centroid(cluster_from_type, from, w_median_point, range_limiters, to)) { return e_create_move::ABORT; } - return ::create_move(blocks_affected, b_from, to); + + e_create_move create_move = ::create_move(blocks_affected, b_from, to); + + //Check that all of the blocks affected by the move would still be in a legal floorplan region after the swap + if (!floorplan_legal(blocks_affected)) { + return e_create_move::ABORT; + } + + return create_move; } /**