Skip to content

Commit 7fb8815

Browse files
authored
Merge pull request #2046 from verilog-to-routing/analytical_placement
analytical placement's bugs are fixed
2 parents c23d6f0 + cf00c56 commit 7fb8815

File tree

5 files changed

+137
-80
lines changed

5 files changed

+137
-80
lines changed

vpr/src/place/analytic_placer.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,18 @@ void AnalyticPlacer::setup_solve_blks(t_logical_block_type_ptr blkTypes) {
412412
void AnalyticPlacer::update_macros() {
413413
for (auto& macro : g_vpr_ctx.mutable_placement().pl_macros) {
414414
ClusterBlockId head_id = macro.members[0].blk_index;
415+
bool mac_can_be_placed = macro_can_be_placed(macro, blk_locs[head_id].loc, true);
416+
417+
//if macro can not be placed in this head pos, change the head pos
418+
if (!mac_can_be_placed) {
419+
size_t macro_size = macro.members.size();
420+
blk_locs[head_id].loc -= macro.members[macro_size - 1].offset;
421+
}
422+
423+
//macro should be placed successfully after changing the head position
424+
VTR_ASSERT(macro_can_be_placed(macro, blk_locs[head_id].loc, true));
425+
426+
//update other member's location based on head pos
415427
for (auto member = ++macro.members.begin(); member != macro.members.end(); ++member) {
416428
blk_locs[member->blk_index].loc = blk_locs[head_id].loc + member->offset;
417429
}

vpr/src/place/cut_spreader.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# include "vtr_time.h"
1212
# include "globals.h"
1313
# include "vtr_log.h"
14+
# include "place_util.h"
1415

1516
// sentinel for base case in CutSpreader (i.e. only 1 block left in region)
1617
constexpr std::pair<int, int> BASE_CASE = {-2, -2};
@@ -173,13 +174,17 @@ void CutSpreader::init() {
173174
}
174175
}
175176

176-
int CutSpreader::occ_at(int x, int y) { return occupancy[x][y]; }
177+
int CutSpreader::occ_at(int x, int y) {
178+
if (!is_loc_on_chip(x, y)) {
179+
return 0;
180+
}
181+
return occupancy[x][y];
182+
}
177183

178184
int CutSpreader::tiles_at(int x, int y) {
179-
int max_x = g_vpr_ctx.device().grid.width();
180-
int max_y = g_vpr_ctx.device().grid.height();
181-
if (x >= max_x || y >= max_y)
185+
if (!is_loc_on_chip(x, y)) {
182186
return 0;
187+
}
183188
return int(subtiles_at_location[x][y].size());
184189
}
185190

@@ -195,7 +200,13 @@ int CutSpreader::tiles_at(int x, int y) {
195200
void CutSpreader::merge_regions(SpreaderRegion& merged, SpreaderRegion& mergee) {
196201
for (int x = mergee.bb.xmin(); x <= mergee.bb.xmax(); x++)
197202
for (int y = mergee.bb.ymin(); y <= mergee.bb.ymax(); y++) {
198-
VTR_ASSERT(reg_id_at_grid[x][y] == mergee.id);
203+
if (!is_loc_on_chip(x, y)) { //location is not within the chip
204+
continue;
205+
}
206+
//x and y might belong to "merged" region already, no further action is required
207+
if (merged.id == reg_id_at_grid[x][y]) {
208+
continue;
209+
}
199210
reg_id_at_grid[x][y] = merged.id; //change group id at mergee grids to merged id
200211
//adds all n_blks and n_tiles from mergee to merged region
201212
merged.n_blks += occ_at(x, y);
@@ -223,6 +234,10 @@ void CutSpreader::grow_region(SpreaderRegion& r, vtr::Rect<int> rect_to_include,
223234
r.bb.expand_bounding_box(rect_to_include);
224235

225236
auto process_location = [&](int x, int y) {
237+
//x and y should represent a location on the chip, otherwise no processing is required
238+
if (!is_loc_on_chip(x, y)) {
239+
return;
240+
}
226241
// kicks in only when grid is not claimed, claimed by another region, or part of a macro
227242
// Merge with any overlapping regions
228243
if (reg_id_at_grid[x][y] == AP_NO_REGION) {
@@ -753,7 +768,7 @@ void CutSpreader::linear_spread_subarea(std::vector<ClusterBlockId>& cut_blks,
753768
// new location is stored back into rawx/rawy
754769
auto& blk_pos = dir ? ap->blk_locs[cut_blks.at(i_blk)].rawy
755770
: ap->blk_locs[cut_blks.at(i_blk)].rawx;
756-
VTR_ASSERT(blk_pos >= group_left && blk_pos <= group_right);
771+
757772
blk_pos = bin_left + mapping * (blk_pos - group_left); // linear interpolation
758773
}
759774
}
@@ -862,7 +877,7 @@ void CutSpreader::strict_legalize() {
862877
}
863878

864879
// timeout
865-
VTR_ASSERT(total_iters_noreset <= std::max(5000, 8 * int(clb_nlist.blocks().size())));
880+
// VTR_ASSERT(total_iters_noreset <= std::max(5000, 8 * int(clb_nlist.blocks().size())));
866881

867882
while (!placed) { // while blk is not placed
868883
// timeout

vpr/src/place/initial_placement.cpp

Lines changed: 1 addition & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,6 @@ constexpr int INVALID_X = -1;
3535
* legal position and place it during initial placement. */
3636
#define MAX_NUM_TRIES_TO_PLACE_MACROS_RANDOMLY 8
3737

38-
/*
39-
* Checks that the placement location is legal for each macro member by applying
40-
* the member's offset to the head position and checking that the resulting
41-
* spot is free, on the chip, etc.
42-
* Returns true if the macro can be placed at the given head position, false if not.
43-
*/
44-
static bool macro_can_be_placed(t_pl_macro pl_macro, t_pl_loc head_pos);
45-
4638
/*
4739
* Places the macro if the head position passed in is legal, and all the resulting
4840
* member positions are legal
@@ -124,12 +116,6 @@ static void print_unplaced_blocks() {
124116
}
125117
}
126118

127-
static bool is_loc_on_chip(t_pl_loc& loc) {
128-
auto& device_ctx = g_vpr_ctx.device();
129-
130-
return (loc.x >= 0 && loc.x < int(device_ctx.grid.width()) && loc.y >= 0 && loc.y < int(device_ctx.grid.height()));
131-
}
132-
133119
static bool is_block_placed(ClusterBlockId blk_id) {
134120
auto& place_ctx = g_vpr_ctx.placement();
135121

@@ -284,64 +270,6 @@ static bool try_exhaustive_placement(t_pl_macro pl_macro, PartitionRegion& pr, t
284270
return placed;
285271
}
286272

287-
static bool macro_can_be_placed(t_pl_macro pl_macro, t_pl_loc head_pos) {
288-
auto& device_ctx = g_vpr_ctx.device();
289-
auto& place_ctx = g_vpr_ctx.placement();
290-
auto& cluster_ctx = g_vpr_ctx.clustering();
291-
292-
//Get block type of head member
293-
ClusterBlockId blk_id = pl_macro.members[0].blk_index;
294-
auto block_type = cluster_ctx.clb_nlist.block_type(blk_id);
295-
296-
// Every macro can be placed until proven otherwise
297-
bool mac_can_be_placed = true;
298-
299-
//Check whether macro contains blocks with floorplan constraints
300-
bool macro_constrained = is_macro_constrained(pl_macro);
301-
302-
// Check whether all the members can be placed
303-
for (size_t imember = 0; imember < pl_macro.members.size(); imember++) {
304-
t_pl_loc member_pos = head_pos + pl_macro.members[imember].offset;
305-
306-
//Check that the member location is on the grid
307-
if (!is_loc_on_chip(member_pos)) {
308-
mac_can_be_placed = false;
309-
break;
310-
}
311-
312-
/*
313-
* If the macro is constrained, check that the head member is in a legal position from
314-
* a floorplanning perspective. It is enough to do this check for the head member alone,
315-
* because constraints propagation was performed to calculate smallest floorplan region for the head
316-
* macro, based on the constraints on all of the blocks in the macro. So, if the head macro is in a
317-
* legal floorplan location, all other blocks in the macro will be as well.
318-
*/
319-
if (macro_constrained && imember == 0) {
320-
bool member_loc_good = cluster_floorplanning_legal(pl_macro.members[imember].blk_index, member_pos);
321-
if (!member_loc_good) {
322-
mac_can_be_placed = false;
323-
break;
324-
}
325-
}
326-
327-
// Check whether the location could accept block of this type
328-
// Then check whether the location could still accommodate more blocks
329-
// Also check whether the member position is valid, and the member_z is allowed at that location on the grid
330-
if (member_pos.x < int(device_ctx.grid.width()) && member_pos.y < int(device_ctx.grid.height())
331-
&& is_tile_compatible(device_ctx.grid[member_pos.x][member_pos.y].type, block_type)
332-
&& place_ctx.grid_blocks[member_pos.x][member_pos.y].blocks[member_pos.sub_tile] == EMPTY_BLOCK_ID) {
333-
// Can still accommodate blocks here, check the next position
334-
continue;
335-
} else {
336-
// Cant be placed here - skip to the next try
337-
mac_can_be_placed = false;
338-
break;
339-
}
340-
}
341-
342-
return (mac_can_be_placed);
343-
}
344-
345273
static bool try_place_macro(t_pl_macro pl_macro, t_pl_loc head_pos) {
346274
auto& place_ctx = g_vpr_ctx.mutable_placement();
347275

@@ -352,7 +280,7 @@ static bool try_place_macro(t_pl_macro pl_macro, t_pl_loc head_pos) {
352280
return (macro_placed);
353281
}
354282

355-
bool mac_can_be_placed = macro_can_be_placed(pl_macro, head_pos);
283+
bool mac_can_be_placed = macro_can_be_placed(pl_macro, head_pos, false);
356284

357285
if (mac_can_be_placed) {
358286
// Place down the macro

vpr/src/place/place_util.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "place_util.h"
88
#include "globals.h"
99
#include "draw_global.h"
10+
#include "place_constraints.h"
1011

1112
/* File-scope routines */
1213
static vtr::Matrix<t_grid_blocks> init_grid_blocks();
@@ -462,3 +463,71 @@ void set_block_location(ClusterBlockId blk_id, const t_pl_loc& location) {
462463
place_ctx.grid_blocks[location.x][location.y].blocks[location.sub_tile] = blk_id;
463464
place_ctx.grid_blocks[location.x][location.y].usage++;
464465
}
466+
467+
bool macro_can_be_placed(t_pl_macro pl_macro, t_pl_loc head_pos, bool check_all_legality) {
468+
auto& device_ctx = g_vpr_ctx.device();
469+
auto& place_ctx = g_vpr_ctx.placement();
470+
auto& cluster_ctx = g_vpr_ctx.clustering();
471+
472+
//Get block type of head member
473+
ClusterBlockId blk_id = pl_macro.members[0].blk_index;
474+
auto block_type = cluster_ctx.clb_nlist.block_type(blk_id);
475+
476+
// Every macro can be placed until proven otherwise
477+
bool mac_can_be_placed = true;
478+
479+
// Check whether all the members can be placed
480+
for (size_t imember = 0; imember < pl_macro.members.size(); imember++) {
481+
t_pl_loc member_pos = head_pos + pl_macro.members[imember].offset;
482+
483+
//Check that the member location is on the grid
484+
if (!is_loc_on_chip(member_pos.x, member_pos.y)) {
485+
mac_can_be_placed = false;
486+
break;
487+
}
488+
489+
/*
490+
* analytical placement approach do not need to make sure whether location could accommodate more blocks
491+
* since overused locations will be spreaded by legalizer afterward.
492+
* floorplan constraint is not supported by analytical placement yet,
493+
* hence, if macro_can_be_placed is called from analytical placer, no further actions are required.
494+
*/
495+
if (check_all_legality) {
496+
continue;
497+
}
498+
499+
//Check whether macro contains blocks with floorplan constraints
500+
bool macro_constrained = is_macro_constrained(pl_macro);
501+
502+
/*
503+
* If the macro is constrained, check that the head member is in a legal position from
504+
* a floorplanning perspective. It is enough to do this check for the head member alone,
505+
* because constraints propagation was performed to calculate smallest floorplan region for the head
506+
* macro, based on the constraints on all of the blocks in the macro. So, if the head macro is in a
507+
* legal floorplan location, all other blocks in the macro will be as well.
508+
*/
509+
if (macro_constrained && imember == 0) {
510+
bool member_loc_good = cluster_floorplanning_legal(pl_macro.members[imember].blk_index, member_pos);
511+
if (!member_loc_good) {
512+
mac_can_be_placed = false;
513+
break;
514+
}
515+
}
516+
517+
// Check whether the location could accept block of this type
518+
// Then check whether the location could still accommodate more blocks
519+
// Also check whether the member position is valid, and the member_z is allowed at that location on the grid
520+
if (member_pos.x < int(device_ctx.grid.width()) && member_pos.y < int(device_ctx.grid.height())
521+
&& is_tile_compatible(device_ctx.grid[member_pos.x][member_pos.y].type, block_type)
522+
&& place_ctx.grid_blocks[member_pos.x][member_pos.y].blocks[member_pos.sub_tile] == EMPTY_BLOCK_ID) {
523+
// Can still accommodate blocks here, check the next position
524+
continue;
525+
} else {
526+
// Cant be placed here - skip to the next try
527+
mac_can_be_placed = false;
528+
break;
529+
}
530+
}
531+
532+
return (mac_can_be_placed);
533+
}

vpr/src/place/place_util.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "vpr_types.h"
1111
#include "vtr_util.h"
1212
#include "vtr_vector_map.h"
13+
#include "globals.h"
1314

1415
/**
1516
* @brief Data structure that stores different cost values in the placer.
@@ -221,4 +222,36 @@ void alloc_and_load_legal_placement_locations(std::vector<std::vector<std::vecto
221222

222223
///@brief Performs error checking to see if location is legal for block type, and sets the location and grid usage of the block if it is legal.
223224
void set_block_location(ClusterBlockId blk_id, const t_pl_loc& location);
225+
226+
/// @brief check if a specified location is within the device grid
227+
inline bool is_loc_on_chip(int x, int y) {
228+
auto& device_ctx = g_vpr_ctx.device();
229+
//return false if the location is not within the chip
230+
return (x >= 0 && x < int(device_ctx.grid.width()) && y >= 0 && y < int(device_ctx.grid.height()));
231+
}
232+
233+
/**
234+
* @brief Checks that each macro member location is legal based on the head position and its offset
235+
*
236+
* If the function is called from initial placement or simulated annealing placer,
237+
* it should ensure that the macro placement is entirely legal. Each macro member
238+
* should be placed in a location with the right type that can accommodate more
239+
* blocks, and floorplanning constraint should also be checked.
240+
* If the function is called from analytical placement, it should only ensure
241+
* that all macro members are placed within the chip. The overused blocks will
242+
* be spread by the strict_legalizer function. Floorplanning constraint is also not supported
243+
* by analytical placer.
244+
*
245+
* @param pl_macro
246+
* macro's member can be accessible from pl_macro parameter.
247+
* @param head_pos
248+
* head_pos is the macro's head location.
249+
* @param check_all_legality
250+
* determines whether the routine should check all legality constraint
251+
* Analytic placer does not require to check block's capacity or
252+
* floorplanning constraints. However, initial placement or SA-based approach
253+
* require to check for all legality constraints.
254+
*/
255+
bool macro_can_be_placed(t_pl_macro pl_macro, t_pl_loc head_pos, bool check_all_legality);
256+
224257
#endif

0 commit comments

Comments
 (0)