Skip to content

Commit 6e442d1

Browse files
authored
Merge pull request #1751 from verilog-to-routing/constraints_propagation
Add constraints propagation to update the PartitionRegions of blocks …
2 parents 35f90c9 + 5fe84dd commit 6e442d1

File tree

4 files changed

+165
-25
lines changed

4 files changed

+165
-25
lines changed

vpr/src/place/initial_placement.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,22 @@ static int check_macro_can_be_placed(t_pl_macro pl_macro, int itype, t_pl_loc he
8282
// Every macro can be placed until proven otherwise
8383
int macro_can_be_placed = true;
8484

85+
//Check whether macro contains blocks with floorplan constraints
8586
bool macro_constrained = is_macro_constrained(pl_macro);
86-
PartitionRegion macro_pr;
87-
88-
if (macro_constrained) {
89-
macro_pr = constrained_macro_locs(pl_macro);
90-
}
9187

9288
// Check whether all the members can be placed
9389
for (size_t imember = 0; imember < pl_macro.members.size(); imember++) {
9490
t_pl_loc member_pos = head_pos + pl_macro.members[imember].offset;
9591

96-
//if the macro is constrained, check if the member position is within the PartitionRegion for the macro
97-
if (macro_constrained) {
98-
bool member_loc_good = macro_pr.is_loc_in_part_reg(member_pos);
92+
/*
93+
* If the macro is constrained, check that the head member is in a legal position from
94+
* a floorplanning perspective. It is enough to do this check for the head member alone,
95+
* because constraints propagation was performed to calculate smallest floorplan region for the head
96+
* macro, based on the constraints on all of the blocks in the macro. So, if the head macro is in a
97+
* legal floorplan location, all other blocks in the macro will be as well.
98+
*/
99+
if (macro_constrained && imember == 0) {
100+
bool member_loc_good = cluster_floorplanning_legal(pl_macro.members[imember].blk_index, member_pos);
99101
if (!member_loc_good) {
100102
macro_can_be_placed = false;
101103
break;
@@ -417,6 +419,11 @@ void initial_placement(enum e_pad_loc_type pad_loc_type, const char* constraints
417419
vtr::vector<ClusterBlockId, t_block_score> block_scores = assign_block_scores();
418420
std::vector<ClusterBlockId> sorted_blocks = sort_blocks(block_scores);
419421

422+
/* Go through cluster blocks to calculate the tightest placement
423+
* floorplan constraint for each constrained block
424+
*/
425+
propagate_place_constraints();
426+
420427
// Loading legal placement locations
421428
zero_initialize_grid_blocks();
422429
alloc_and_load_legal_placement_locations(legal_pos);

vpr/src/place/place_constraints.cpp

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ bool is_macro_constrained(const t_pl_macro& pl_macro) {
5454
}
5555

5656
/*Returns PartitionRegion of where the head of the macro could go*/
57-
PartitionRegion constrained_macro_locs(const t_pl_macro& pl_macro) {
58-
PartitionRegion macro_pr;
57+
PartitionRegion update_macro_head_pr(const t_pl_macro& pl_macro, const PartitionRegion& grid_pr) {
58+
PartitionRegion macro_head_pr;
5959
bool is_member_constrained = false;
6060
int num_constrained_members = 0;
6161
auto& floorplanning_ctx = g_vpr_ctx.floorplanning();
@@ -80,39 +80,116 @@ PartitionRegion constrained_macro_locs(const t_pl_macro& pl_macro) {
8080

8181
vtr::Rect<int> reg_rect = block_regions[i].get_region_rect();
8282

83-
t_pl_loc min_pl_loc(reg_rect.xmin(), reg_rect.ymin(), block_regions[i].get_sub_tile());
84-
85-
t_pl_loc modified_min_pl_loc = min_pl_loc + offset;
86-
87-
t_pl_loc max_pl_loc(reg_rect.xmax(), reg_rect.ymax(), block_regions[i].get_sub_tile());
83+
modified_reg.set_region_rect(reg_rect.xmin() - offset.x, reg_rect.ymin() - offset.y, reg_rect.xmax() - offset.x, reg_rect.ymax() - offset.y);
8884

89-
t_pl_loc modified_max_pl_loc = max_pl_loc + offset;
90-
91-
modified_reg.set_region_rect(modified_min_pl_loc.x, modified_min_pl_loc.y, modified_max_pl_loc.x, modified_max_pl_loc.y);
9285
//check that subtile is not an invalid value before changing, otherwise it just stays -1
93-
if (block_regions[i].get_sub_tile() != -1) {
94-
modified_reg.set_sub_tile(modified_min_pl_loc.sub_tile);
86+
if (block_regions[i].get_sub_tile() != NO_SUBTILE) {
87+
modified_reg.set_sub_tile(block_regions[i].get_sub_tile() - offset.sub_tile);
9588
}
9689

9790
modified_pr.add_to_part_region(modified_reg);
9891
}
9992

10093
if (num_constrained_members == 1) {
101-
macro_pr = modified_pr;
94+
macro_head_pr = modified_pr;
10295
} else {
103-
macro_pr = intersection(macro_pr, modified_pr);
96+
macro_head_pr = intersection(macro_head_pr, modified_pr);
10497
}
10598
}
10699
}
107100

101+
//intersect to ensure the head pr does not go outside of grid dimensions
102+
macro_head_pr = intersection(macro_head_pr, grid_pr);
103+
104+
//if the intersection is empty, no way to place macro members together, give an error
105+
if (macro_head_pr.empty()) {
106+
print_macro_constraint_error(pl_macro);
107+
}
108+
109+
return macro_head_pr;
110+
}
111+
112+
PartitionRegion update_macro_member_pr(PartitionRegion& head_pr, const t_pl_offset& offset, const PartitionRegion& grid_pr, const t_pl_macro& pl_macro) {
113+
std::vector<Region> block_regions = head_pr.get_partition_region();
114+
PartitionRegion macro_pr;
115+
116+
for (unsigned int i = 0; i < block_regions.size(); i++) {
117+
Region modified_reg;
118+
119+
vtr::Rect<int> reg_rect = block_regions[i].get_region_rect();
120+
121+
modified_reg.set_region_rect(reg_rect.xmin() + offset.x, reg_rect.ymin() + offset.y, reg_rect.xmax() + offset.x, reg_rect.ymax() + offset.y);
122+
123+
//check that subtile is not an invalid value before changing, otherwise it just stays -1
124+
if (block_regions[i].get_sub_tile() != NO_SUBTILE) {
125+
modified_reg.set_sub_tile(block_regions[i].get_sub_tile() + offset.sub_tile);
126+
}
127+
128+
macro_pr.add_to_part_region(modified_reg);
129+
}
130+
131+
//intersect to ensure the macro pr does not go outside of grid dimensions
132+
macro_pr = intersection(macro_pr, grid_pr);
133+
108134
//if the intersection is empty, no way to place macro members together, give an error
109135
if (macro_pr.empty()) {
110-
VPR_ERROR(VPR_ERROR_PLACE, " \n Feasible floorplanning constraints could not be calculated for the placement macro.\n");
136+
print_macro_constraint_error(pl_macro);
111137
}
112138

113139
return macro_pr;
114140
}
115141

142+
void print_macro_constraint_error(const t_pl_macro& pl_macro) {
143+
auto& cluster_ctx = g_vpr_ctx.clustering();
144+
VTR_LOG(
145+
"Feasible floorplanning constraints could not be calculated for the placement macro. \n"
146+
"The placement macro contains the following blocks: \n");
147+
for (unsigned int i = 0; i < pl_macro.members.size(); i++) {
148+
std::string blk_name = cluster_ctx.clb_nlist.block_name((pl_macro.members[i].blk_index));
149+
VTR_LOG("Block %s (#%zu) ", blk_name.c_str(), size_t(pl_macro.members[i].blk_index));
150+
}
151+
VTR_LOG("\n");
152+
VPR_ERROR(VPR_ERROR_PLACE, " \n Check that the above-mentioned placement macro blocks have compatible floorplan constraints.\n");
153+
}
154+
155+
void propagate_place_constraints() {
156+
auto& place_ctx = g_vpr_ctx.placement();
157+
auto& floorplanning_ctx = g_vpr_ctx.mutable_floorplanning();
158+
auto& device_ctx = g_vpr_ctx.device();
159+
160+
//Create a PartitionRegion with grid dimensions
161+
//Will be used to check that updated PartitionRegions are within grid bounds
162+
int width = device_ctx.grid.width() - 1;
163+
int height = device_ctx.grid.height() - 1;
164+
Region grid_reg;
165+
grid_reg.set_region_rect(0, 0, width, height);
166+
PartitionRegion grid_pr;
167+
grid_pr.add_to_part_region(grid_reg);
168+
169+
for (auto pl_macro : place_ctx.pl_macros) {
170+
if (is_macro_constrained(pl_macro)) {
171+
/*
172+
* Get the PartitionRegion for the head of the macro
173+
* based on the constraints of all blocks contained in the macro
174+
*/
175+
PartitionRegion macro_head_pr = update_macro_head_pr(pl_macro, grid_pr);
176+
177+
//Update PartitionRegions of all members of the macro
178+
for (size_t imember = 0; imember < pl_macro.members.size(); imember++) {
179+
ClusterBlockId iblk = pl_macro.members[imember].blk_index;
180+
auto offset = pl_macro.members[imember].offset;
181+
182+
if (imember == 0) { //Update head PR
183+
floorplanning_ctx.cluster_constraints[iblk] = macro_head_pr;
184+
} else { //Update macro member PR
185+
PartitionRegion macro_pr = update_macro_member_pr(macro_head_pr, offset, grid_pr, pl_macro);
186+
floorplanning_ctx.cluster_constraints[iblk] = macro_pr;
187+
}
188+
}
189+
}
190+
}
191+
}
192+
116193
/*returns true if location is compatible with floorplanning constraints, false if not*/
117194
/*
118195
* Even if the block passed in is from a macro, it will work because of the constraints

vpr/src/place/place_constraints.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,33 @@ bool cluster_floorplanning_legal(ClusterBlockId blk_id, const t_pl_loc& loc);
3434
bool is_macro_constrained(const t_pl_macro& pl_macro);
3535

3636
/*
37-
* Returns region of valid locations for the head of the macro based on floorplan constraints
37+
* Returns PartitionRegion for the head of the macro based on the floorplan constraints
38+
* of all blocks in the macro. For example, if there was a macro of length two and each block has
39+
* a constraint, this routine will shift and intersect the two constraint regions to calculate
40+
* the tightest region constraint for the head macro.
3841
*/
39-
PartitionRegion constrained_macro_locs(const t_pl_macro& pl_macro);
42+
PartitionRegion update_macro_head_pr(const t_pl_macro& pl_macro, const PartitionRegion& grid_pr);
43+
44+
/*
45+
* Update the PartitionRegions of non-head members of a macro,
46+
* based on the constraint that was calculated for the head region, head_pr.
47+
* The constraint on the head region must be the tightest possible (i.e. implied by the
48+
* entire macro) before this routine is called.
49+
* For each macro member, the updated constraint is essentially the head constraint
50+
* with the member's offset applied.
51+
*/
52+
PartitionRegion update_macro_member_pr(PartitionRegion& head_pr, const t_pl_offset& offset, const PartitionRegion& grid_pr, const t_pl_macro& pl_macro);
53+
54+
/*
55+
* Updates the floorplan constraints information for all constrained macros.
56+
* Updates the constraints to be the tightest constraints possible while adhering
57+
* to the floorplan constraints of each macro member.
58+
* This is done at the start of initial placement to ease floorplan legality checking
59+
* while placing macros during initial placement.
60+
*/
61+
void propagate_place_constraints();
62+
63+
void print_macro_constraint_error(const t_pl_macro& pl_macro);
4064

4165
inline bool floorplan_legal(const t_pl_blocks_to_be_moved& blocks_affected) {
4266
bool floorplan_legal;

vpr/test/test_vpr_constraints.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "vpr_constraints.h"
77
#include "partition.h"
88
#include "region.h"
9+
#include "place_constraints.h"
910

1011
/**
1112
* This file contains unit tests that check the functionality of all classes related to vpr constraints. These classes include
@@ -425,6 +426,37 @@ TEST_CASE("RegionLocked", "[vpr]") {
425426
REQUIRE(is_r2_locked == false);
426427
}
427428

429+
//Test calculation of macro constraints
430+
/* Checks that the PartitionRegion of a macro member is updated properly according
431+
* to the head member's PartitionRegion that is passed in.
432+
*/
433+
TEST_CASE("MacroConstraints", "[vpr]") {
434+
t_pl_macro pl_macro;
435+
PartitionRegion head_pr;
436+
t_pl_offset offset(2, 1, 0);
437+
438+
Region reg;
439+
reg.set_region_rect(5, 2, 9, 6);
440+
441+
head_pr.add_to_part_region(reg);
442+
443+
Region grid_reg;
444+
grid_reg.set_region_rect(0, 0, 20, 20);
445+
PartitionRegion grid_pr;
446+
grid_pr.add_to_part_region(grid_reg);
447+
448+
PartitionRegion macro_pr = update_macro_member_pr(head_pr, offset, grid_pr, pl_macro);
449+
450+
std::vector<Region> mac_regions = macro_pr.get_partition_region();
451+
452+
vtr::Rect<int> mac_rect = mac_regions[0].get_region_rect();
453+
454+
REQUIRE(mac_rect.xmin() == 7);
455+
REQUIRE(mac_rect.ymin() == 3);
456+
REQUIRE(mac_rect.xmax() == 11);
457+
REQUIRE(mac_rect.ymax() == 7);
458+
}
459+
428460
static constexpr const char kArchFile[] = "test_read_arch_metadata.xml";
429461

430462
// Test that place constraints are not changed during placement

0 commit comments

Comments
 (0)