Skip to content

Commit fb75430

Browse files
authored
Merge pull request #1938 from verilog-to-routing/generate_test_constraints_files
Automatically generate floorplan test files after placement, and enhancements to cluster attraction groups
2 parents 66ffeaa + ca7d60a commit fb75430

23 files changed

+844
-131
lines changed

vpr/src/base/SetupVPR.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,8 @@ static void SetupPlacerOpts(const t_options& Options, t_placer_opts* PlacerOpts)
613613
PlacerOpts->place_agent_algorithm = Options.place_agent_algorithm;
614614
PlacerOpts->place_constraint_expand = Options.place_constraint_expand;
615615
PlacerOpts->place_constraint_subtile = Options.place_constraint_subtile;
616+
PlacerOpts->floorplan_num_horizontal_partitions = Options.floorplan_num_horizontal_partitions;
617+
PlacerOpts->floorplan_num_vertical_partitions = Options.floorplan_num_vertical_partitions;
616618
}
617619

618620
static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysis_opts) {

vpr/src/base/read_options.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,6 +2024,22 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg
20242024
.default_value("off")
20252025
.show_in(argparse::ShowIn::HELP_ONLY);
20262026

2027+
place_grp.add_argument(args.floorplan_num_horizontal_partitions, "--floorplan_num_horizontal_partitions")
2028+
.help(
2029+
"An argument used for generating test constraints files. Specifies how many partitions to "
2030+
"make in the horizontal dimension. Must be used in conjunction with "
2031+
"--floorplan_num_vertical_partitions")
2032+
.default_value("0")
2033+
.show_in(argparse::ShowIn::HELP_ONLY);
2034+
2035+
place_grp.add_argument(args.floorplan_num_vertical_partitions, "--floorplan_num_vertical_partitions")
2036+
.help(
2037+
"An argument used for generating test constraints files. Specifies how many partitions to "
2038+
"make in the vertical dimension. Must be used in conjunction with "
2039+
"--floorplan_num_horizontal_partitions")
2040+
.default_value("0")
2041+
.show_in(argparse::ShowIn::HELP_ONLY);
2042+
20272043
/*
20282044
* place_grp.add_argument(args.place_timing_cost_func, "--place_timing_cost_func")
20292045
* .help(

vpr/src/base/read_options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ struct t_options {
135135
argparse::ArgValue<float> place_crit_limit;
136136
argparse::ArgValue<int> place_constraint_expand;
137137
argparse::ArgValue<bool> place_constraint_subtile;
138+
argparse::ArgValue<int> floorplan_num_horizontal_partitions;
139+
argparse::ArgValue<int> floorplan_num_vertical_partitions;
138140

139141
/* Timing-driven placement options only */
140142
argparse::ArgValue<float> PlaceTimingTradeoff;

vpr/src/base/region.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ class Region {
5858
*/
5959
bool is_loc_in_reg(t_pl_loc loc);
6060

61+
bool operator==(const Region& reg) const {
62+
return (reg.get_region_rect() == this->get_region_rect() && reg.get_sub_tile() == this->get_sub_tile());
63+
}
64+
6165
private:
6266
//may need to include zmin, zmax for future use in 3D FPGA designs
6367
vtr::Rect<int> region_bounds; ///< xmin, ymin, xmax, ymax inclusive
@@ -88,4 +92,19 @@ Region intersection(const Region& r1, const Region& r2);
8892
///@brief Used to print data from a Region
8993
void print_region(FILE* fp, Region region);
9094

95+
namespace std {
96+
template<>
97+
struct hash<Region> {
98+
std::size_t operator()(const Region& reg) const noexcept {
99+
vtr::Rect<int> rect = reg.get_region_rect();
100+
std::size_t seed = std::hash<int>{}(rect.xmin());
101+
vtr::hash_combine(seed, rect.ymin());
102+
vtr::hash_combine(seed, rect.xmax());
103+
vtr::hash_combine(seed, rect.ymax());
104+
vtr::hash_combine(seed, reg.get_sub_tile());
105+
return seed;
106+
}
107+
};
108+
} // namespace std
109+
91110
#endif /* REGION_H */

vpr/src/base/vpr_api.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,8 @@ bool vpr_place_flow(t_vpr_setup& vpr_setup, const t_arch& arch) {
632632

633633
//Write out a vpr floorplanning constraints file if the option is specified
634634
if (!filename_opts.write_vpr_constraints_file.empty()) {
635-
write_vpr_floorplan_constraints(filename_opts.write_vpr_constraints_file.c_str(), placer_opts.place_constraint_expand, placer_opts.place_constraint_subtile);
635+
write_vpr_floorplan_constraints(filename_opts.write_vpr_constraints_file.c_str(), placer_opts.place_constraint_expand, placer_opts.place_constraint_subtile,
636+
placer_opts.floorplan_num_horizontal_partitions, placer_opts.floorplan_num_vertical_partitions);
636637
}
637638

638639
return true;

vpr/src/base/vpr_constraints.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
#include "partition.h"
33

44
void VprConstraints::add_constrained_atom(const AtomBlockId blk_id, const PartitionId part_id) {
5-
constrained_atoms.insert({blk_id, part_id});
6-
75
auto got = constrained_atoms.find(blk_id);
86

97
/**
10-
* Each atom can only be in one partition. If the atoms already has a partition id assigned to it,
11-
* the id will be switched to the new part_id being passed in instead
8+
* Each atom can only be in one partition. If the atom is not found in constrained_atoms, it
9+
* will be added with its partition id.
10+
* If the atom is already in constrained_atoms, the partition id will be updated.
1211
*/
1312
if (got == constrained_atoms.end()) {
1413
constrained_atoms.insert({blk_id, part_id});

vpr/src/base/vpr_constraints_writer.cpp

Lines changed: 139 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717

1818
#include <fstream>
1919
#include "vpr_constraints_writer.h"
20+
#include "region.h"
2021

21-
void write_vpr_floorplan_constraints(const char* file_name, int expand, bool subtile) {
22-
//Fill in the constraints object to be printed out.
22+
void write_vpr_floorplan_constraints(const char* file_name, int expand, bool subtile, int horizontal_partitions, int vertical_partitions) {
2323
VprConstraints constraints;
2424

25-
setup_vpr_floorplan_constraints(constraints, expand, subtile);
25+
if (horizontal_partitions != 0 && vertical_partitions != 0) {
26+
setup_vpr_floorplan_constraints_cutpoints(constraints, horizontal_partitions, vertical_partitions);
27+
} else {
28+
setup_vpr_floorplan_constraints_one_loc(constraints, expand, subtile);
29+
}
2630

2731
VprConstraintsSerializer writer(constraints);
2832

@@ -39,7 +43,7 @@ void write_vpr_floorplan_constraints(const char* file_name, int expand, bool sub
3943
}
4044
}
4145

42-
void setup_vpr_floorplan_constraints(VprConstraints& constraints, int expand, bool subtile) {
46+
void setup_vpr_floorplan_constraints_one_loc(VprConstraints& constraints, int expand, bool subtile) {
4347
auto& cluster_ctx = g_vpr_ctx.clustering();
4448
auto& place_ctx = g_vpr_ctx.placement();
4549
ClusterAtomsLookup atoms_lookup;
@@ -83,3 +87,134 @@ void setup_vpr_floorplan_constraints(VprConstraints& constraints, int expand, bo
8387
part_id++;
8488
}
8589
}
90+
91+
void setup_vpr_floorplan_constraints_cutpoints(VprConstraints& constraints, int horizontal_cutpoints, int vertical_cutpoints) {
92+
auto& cluster_ctx = g_vpr_ctx.clustering();
93+
auto& place_ctx = g_vpr_ctx.placement();
94+
auto& device_ctx = g_vpr_ctx.device();
95+
ClusterAtomsLookup atoms_lookup;
96+
97+
//calculate the cutpoint values according to the grid size
98+
//load two arrays - one for horizontal cutpoints and one for vertical
99+
100+
std::vector<int> horizontal_cuts;
101+
102+
std::vector<int> vertical_cuts;
103+
104+
int horizontal_interval = device_ctx.grid.width() / horizontal_cutpoints;
105+
VTR_LOG("Device grid width is %d, horizontal interval is %d\n", device_ctx.grid.width(), horizontal_interval);
106+
107+
unsigned int horizontal_point = horizontal_interval;
108+
horizontal_cuts.push_back(0);
109+
int num_horizontal_cuts = 0;
110+
while (num_horizontal_cuts < horizontal_cutpoints - 1) {
111+
horizontal_cuts.push_back(horizontal_point);
112+
horizontal_point = horizontal_point + horizontal_interval;
113+
num_horizontal_cuts++;
114+
}
115+
//Add in the last point after your exit the while loop
116+
horizontal_cuts.push_back(device_ctx.grid.width());
117+
118+
int vertical_interval = device_ctx.grid.height() / vertical_cutpoints;
119+
VTR_LOG("Device grid height is %d, vertical interval is %d\n", device_ctx.grid.height(), vertical_interval);
120+
121+
unsigned int vertical_point = vertical_interval;
122+
vertical_cuts.push_back(0);
123+
int num_vertical_cuts = 0;
124+
while (num_vertical_cuts < vertical_cutpoints - 1) {
125+
vertical_cuts.push_back(vertical_point);
126+
vertical_point = vertical_point + vertical_interval;
127+
num_vertical_cuts++;
128+
}
129+
//Add in the last point after your exit the while loop
130+
vertical_cuts.push_back(device_ctx.grid.height());
131+
132+
//Create floorplan regions based on the cutpoints
133+
std::unordered_map<Region, std::vector<AtomBlockId>> region_atoms;
134+
135+
for (unsigned int i = 0; i < horizontal_cuts.size() - 1; i++) {
136+
int xmin = horizontal_cuts[i];
137+
int xmax = horizontal_cuts[i + 1] - 1;
138+
139+
for (unsigned int j = 0; j < vertical_cuts.size() - 1; j++) {
140+
int ymin = vertical_cuts[j];
141+
int ymax = vertical_cuts[j + 1] - 1;
142+
143+
Region reg;
144+
reg.set_region_rect(xmin, ymin, xmax, ymax);
145+
std::vector<AtomBlockId> atoms;
146+
147+
region_atoms.insert({reg, atoms});
148+
}
149+
}
150+
151+
/*
152+
* For each cluster block, see which region it belongs to, and add its atoms to the
153+
* appropriate region accordingly
154+
*/
155+
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
156+
std::vector<AtomBlockId> atoms = atoms_lookup.atoms_in_cluster(blk_id);
157+
int num_atoms = atoms.size();
158+
int x = place_ctx.block_locs[blk_id].loc.x;
159+
int y = place_ctx.block_locs[blk_id].loc.y;
160+
int width = device_ctx.grid.width();
161+
int height = device_ctx.grid.height();
162+
VTR_ASSERT(x >= 0 && x < width);
163+
VTR_ASSERT(y >= 0 && y < height);
164+
int xminimum = 0, yminimum = 0, xmaximum = 0, ymaximum = 0;
165+
166+
for (unsigned int h = 1; h < horizontal_cuts.size(); h++) {
167+
if (x < horizontal_cuts[h]) {
168+
xmaximum = horizontal_cuts[h] - 1;
169+
xminimum = horizontal_cuts[h - 1];
170+
break;
171+
}
172+
}
173+
174+
for (unsigned int v = 1; v < vertical_cuts.size(); v++) {
175+
if (y < vertical_cuts[v]) {
176+
ymaximum = vertical_cuts[v] - 1;
177+
yminimum = vertical_cuts[v - 1];
178+
break;
179+
}
180+
}
181+
182+
Region current_reg;
183+
current_reg.set_region_rect(xminimum, yminimum, xmaximum, ymaximum);
184+
185+
auto got = region_atoms.find(current_reg);
186+
187+
VTR_ASSERT(got != region_atoms.end());
188+
189+
for (int at = 0; at < num_atoms; at++) {
190+
got->second.push_back(atoms[at]);
191+
}
192+
}
193+
194+
int num_partitions = 0;
195+
for (auto region : region_atoms) {
196+
Partition part;
197+
PartitionId partid(num_partitions);
198+
std::string part_name = "Part" + std::to_string(num_partitions);
199+
vtr::Rect<int> rect = region.first.get_region_rect();
200+
create_partition(part, part_name, rect.xmin(), rect.ymin(), rect.xmax(), rect.ymax());
201+
constraints.add_partition(part);
202+
203+
for (unsigned int k = 0; k < region.second.size(); k++) {
204+
constraints.add_constrained_atom(region.second[k], partid);
205+
}
206+
207+
num_partitions++;
208+
}
209+
}
210+
211+
void create_partition(Partition& part, std::string part_name, int xmin, int ymin, int xmax, int ymax) {
212+
part.set_name(part_name);
213+
PartitionRegion part_pr;
214+
Region part_region;
215+
part_region.set_region_rect(xmin, ymin, xmax, ymax);
216+
std::vector<Region> part_regions;
217+
part_regions.push_back(part_region);
218+
part_pr.set_partition_region(part_regions);
219+
part.set_part_region(part_pr);
220+
}

vpr/src/base/vpr_constraints_writer.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,16 @@
1010
* Routines related to writing out the file are in vpr/src/base/vpr_constraints_serializer.h. For more information on how
1111
* the writing interface works, refer to vpr/src/route/SCHEMA_GENERATOR.md
1212
*
13+
* The option --write_vpr_constraints can be used to generate the constraints files.
1314
*
15+
* The routines in this file are currently used to generate floorplan constraints for testing purposes.
16+
* The constraints files they generate are used to determine whether VPR is correctly adhering to
17+
* floorplan constraints during its packing and placement stages.
18+
*
19+
* The placer options --floorplan_num_horizontal_partitions (int) and --floorplan_num_vertical_partitions (int) can be used
20+
* to specify how many partitions should be created in the test constraints file.
21+
* For example, if both options are 2, the constraints file will split the grid into quadrants, dividing the blocks between
22+
* four partitions - two partitions in the horizontal dimension, and two partitions in the vertical dimension.
1423
*/
1524

1625
#ifndef VPR_SRC_BASE_VPR_CONSTRAINTS_WRITER_H_
@@ -26,8 +35,16 @@
2635
* @param subtile Specifies whether to write out the constraint regions with or without
2736
* subtile values.
2837
*/
29-
void write_vpr_floorplan_constraints(const char* file_name, int expand, bool subtile);
38+
void write_vpr_floorplan_constraints(const char* file_name, int expand, bool subtile, int horizontal_partitions, int vertical_partitions);
39+
40+
//Generate constraints which lock all blocks to one location.
41+
void setup_vpr_floorplan_constraints_one_loc(VprConstraints& constraints, int expand, bool subtile);
42+
43+
/* Generate constraints which divide the grid into partition according to the horizontal and vertical partition values passed in
44+
* and lock down blocks to their appropriate partition.
45+
*/
46+
void setup_vpr_floorplan_constraints_cutpoints(VprConstraints& constraints, int horizontal_cutpoints, int vertical_cutpoints);
3047

31-
void setup_vpr_floorplan_constraints(VprConstraints& constraints, int expand, bool subtile);
48+
void create_partition(Partition& part, std::string part_name, int xmin, int ymin, int xmax, int ymax);
3249

3350
#endif /* VPR_SRC_BASE_VPR_CONSTRAINTS_WRITER_H_ */

vpr/src/base/vpr_context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ struct FloorplanningContext : public Context {
377377
* The constraints on each cluster are computed during the clustering process and can change.
378378
*/
379379
vtr::vector<ClusterBlockId, PartitionRegion> cluster_constraints;
380+
381+
std::vector<Region> overfull_regions;
380382
};
381383

382384
/**

vpr/src/base/vpr_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,8 @@ struct t_placer_opts {
10761076
float place_crit_limit;
10771077
int place_constraint_expand;
10781078
bool place_constraint_subtile;
1079+
int floorplan_num_horizontal_partitions;
1080+
int floorplan_num_vertical_partitions;
10791081

10801082
/**
10811083
* @brief Tile types that should be used during delay sampling.

0 commit comments

Comments
 (0)