Skip to content

Mark fixed blocks #1759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cd289a2
Added code for marking down blocks that constrained to one location o…
sfkhalid Jun 2, 2021
8ad3c1b
Region empty function now returns true if the rectangle either has im…
sfkhalid Jun 2, 2021
77786c8
Ran make format
sfkhalid Jun 2, 2021
25a5b7f
Changed default empty region values
sfkhalid Jun 9, 2021
6c6772d
Added helper function for marking block locations and grid usage with…
sfkhalid Jun 9, 2021
bf766f0
Changed placement consistency error messages to improve clarity
sfkhalid Jun 9, 2021
c915129
Add function to count number of tiles covered by a floorplan region
sfkhalid Jun 10, 2021
2f0dbf6
Changed comment
sfkhalid Jun 14, 2021
8165a5d
Changed name of function mark_block_location->set_block_location
sfkhalid Jun 15, 2021
8a90016
Added functions to check whether the PartitionRegion of a cluster blo…
sfkhalid Jun 16, 2021
2cc056b
Ran make format
sfkhalid Jun 16, 2021
904db47
Removed locked member function from Region class - was no longer need…
sfkhalid Jun 16, 2021
4f94cbd
Merge branch 'master' into mark_fixed_blocks
sfkhalid Jun 16, 2021
3a9096b
Got rid of unnecessary lines in mark_fixed_blocks
sfkhalid Jun 16, 2021
e359b20
merge branch 'mark_fixed_blocks' of https://github.com/verilog-to-rou…
sfkhalid Jun 16, 2021
3c9c93a
Ran make format
sfkhalid Jun 16, 2021
e1fa745
Initialized grid blocks earlier in flow of reading in place file
sfkhalid Jun 17, 2021
f2305df
Refactored read_place to make use of set_block_location utility function
sfkhalid Jun 17, 2021
7e0fe58
Improved error messaging during read place
sfkhalid Jun 17, 2021
0504d8c
Refactored region size routine to return an int instead of a bool
sfkhalid Jun 17, 2021
8c3c163
Refactored region tile cover routine to return int instead of bool
sfkhalid Jun 18, 2021
c3ad3b6
Modified is_pr_size_one to get rid of compiler warning
sfkhalid Jun 18, 2021
6ad75c3
Added check to partition region size check to see whether multiple re…
sfkhalid Jun 18, 2021
8887b6c
Added checks for whether subtile location is valid when marking fixed…
sfkhalid Jun 21, 2021
cbe935d
Merge branch 'master' into mark_fixed_blocks
sfkhalid Jun 21, 2021
58e2683
Check whether subtile is compatible when adding fixed blocks
sfkhalid Jun 21, 2021
57ae843
Moved initialization of placement structures during load place flow. …
sfkhalid Jun 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 28 additions & 29 deletions vpr/src/base/read_place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "hash.h"
#include "read_place.h"
#include "read_xml_arch_file.h"
#include "place_util.h"

void read_place_header(
std::ifstream& placement_file,
Expand Down Expand Up @@ -185,6 +186,23 @@ void read_place_body(std::ifstream& placement_file,
place_ctx.block_locs.resize(cluster_ctx.clb_nlist.blocks().size());
}

/*
* If placement is being loaded (i.e. reading in a place file),
* the grid_blocks data structure has not been initialized yet,
* so it is initialized here.
*/
if (is_place_file) {
auto& grid_blocks = place_ctx.grid_blocks;
auto& device_grid = device_ctx.grid;
grid_blocks.resize({device_grid.width(), device_grid.height()});
for (size_t x = 0; x < device_grid.width(); ++x) {
for (size_t y = 0; y < device_grid.height(); ++y) {
auto& grid_block = grid_blocks[x][y];
grid_block.blocks.resize(device_ctx.grid[x][y].type->capacity);
}
}
}

//used to count how many times a block has been seen in the place/constraints file so duplicate blocks can be detected
vtr::vector_map<ClusterBlockId, int> seen_blocks;

Expand Down Expand Up @@ -236,45 +254,26 @@ void read_place_body(std::ifstream& placement_file,
//Check if block is listed multiple times with conflicting locations in constraints file
if (seen_blocks[blk_id] > 0) {
if (block_x != place_ctx.block_locs[blk_id].loc.x || block_y != place_ctx.block_locs[blk_id].loc.y || sub_tile_index != place_ctx.block_locs[blk_id].loc.sub_tile) {
std::string cluster_name = cluster_ctx.clb_nlist.block_name(blk_id);
VPR_THROW(VPR_ERROR_PLACE,
"The location of cluster %d is specified %d times in the constraints file with conflicting locations. \n"
"The location of cluster %s (#%d) is specified %d times in the constraints file with conflicting locations. \n"
"Its location was last specified with block %s. \n",
blk_id, seen_blocks[blk_id] + 1, c_block_name);
cluster_name.c_str(), blk_id, seen_blocks[blk_id] + 1, c_block_name);
}
}

//Check if block location is out of range of grid dimensions
if (block_x < 0 || block_x > int(device_ctx.grid.width() - 1)
|| block_y < 0 || block_y > int(device_ctx.grid.height() - 1)) {
VPR_THROW(VPR_ERROR_PLACE, "Block %s with ID %d is out of range at location (%d, %d). \n", c_block_name, blk_id, block_x, block_y);
}

//Set the location
place_ctx.block_locs[blk_id].loc.x = block_x;
place_ctx.block_locs[blk_id].loc.y = block_y;
place_ctx.block_locs[blk_id].loc.sub_tile = sub_tile_index;

//Check if block is at an illegal location

auto physical_tile = device_ctx.grid[block_x][block_y].type;
auto logical_block = cluster_ctx.clb_nlist.block_type(blk_id);
t_pl_loc loc;
loc.x = block_x;
loc.y = block_y;
loc.sub_tile = sub_tile_index;

if (sub_tile_index >= physical_tile->capacity || sub_tile_index < 0) {
VPR_THROW(VPR_ERROR_PLACE, "Block %s subtile number (%d) is out of range. \n", c_block_name, sub_tile_index);
if (seen_blocks[blk_id] == 0) {
set_block_location(blk_id, loc);
}

if (!is_sub_tile_compatible(physical_tile, logical_block, place_ctx.block_locs[blk_id].loc.sub_tile)) {
VPR_THROW(VPR_ERROR_PLACE, "Attempt to place block %s with ID %d at illegal location (%d, %d). \n", c_block_name, blk_id, block_x, block_y);
}

//need to lock down blocks and mark grid block usage if it is a constraints file
//for a place file, grid usage is marked during initial placement instead
//need to lock down blocks if it is a constraints file
if (!is_place_file) {
place_ctx.block_locs[blk_id].is_fixed = true;
place_ctx.grid_blocks[block_x][block_y].blocks[sub_tile_index] = blk_id;
if (seen_blocks[blk_id] == 0) {
place_ctx.grid_blocks[block_x][block_y].usage++;
}
}

//mark the block as seen
Expand Down
12 changes: 4 additions & 8 deletions vpr/src/base/region.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
Region::Region() {
sub_tile = NO_SUBTILE;

//default rect for a region is (-1, -1, -1, -1)
//default rect for a region is (999, 999, -1, -1)
//these values indicate an empty rectangle, they are set as default values to help catch uninitialized use
region_bounds.set_xmin(-1);
region_bounds.set_ymin(-1);
region_bounds.set_xmin(999);
region_bounds.set_ymin(999);
region_bounds.set_xmax(-1);
region_bounds.set_ymax(-1);
}
Expand All @@ -30,12 +30,8 @@ void Region::set_sub_tile(int _sub_tile) {
sub_tile = _sub_tile;
}

bool Region::locked() {
return region_bounds.xmin() == region_bounds.xmax() && region_bounds.ymin() == region_bounds.ymax() && sub_tile != NO_SUBTILE;
}

bool Region::empty() {
return region_bounds.empty();
return (region_bounds.xmax() < region_bounds.xmin() || region_bounds.ymax() < region_bounds.ymin());
}

bool Region::is_loc_in_reg(t_pl_loc loc) {
Expand Down
8 changes: 2 additions & 6 deletions vpr/src/base/region.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,11 @@ class Region {
void set_sub_tile(int _sub_tile);

/**
* @brief Return whether the region is empty, based on whether the region rectangle is empty
* @brief Return whether the region is empty (i. e. the region bounds rectangle
* covers no area)
*/
bool empty();

/**
* @brief Checks whether a block is locked down to a specific x, y, subtile location
*/
bool locked();

/**
* @brief Check if the location is in the region (at a valid x, y, subtile location within the region bounds, inclusive)
* If the region has no subtile specified, then the location subtile does not have to match. If it does, the location
Expand Down
4 changes: 4 additions & 0 deletions vpr/src/place/initial_placement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,10 @@ void initial_placement(enum e_pad_loc_type pad_loc_type, const char* constraints
read_constraints(constraints_file);
}

/*Mark the blocks that have already been locked to one spot via floorplan constraints
* as fixed so they do not get moved during initial placement or during simulated annealing*/
mark_fixed_blocks();

initial_placement_pl_macros(MAX_NUM_TRIES_TO_PLACE_MACROS_RANDOMLY, free_locations);

// All the macros are placed, update the legal_pos[][] array and free_locations[] array
Expand Down
10 changes: 5 additions & 5 deletions vpr/src/place/place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2644,8 +2644,8 @@ static int check_block_placement_consistency() {
for (size_t i = 0; i < device_ctx.grid.width(); i++)
for (size_t j = 0; j < device_ctx.grid.height(); j++) {
if (place_ctx.grid_blocks[i][j].usage > device_ctx.grid[i][j].type->capacity) {
VTR_LOG_ERROR("Block at grid location (%zu,%zu) overused. Usage is %d.\n",
i, j, place_ctx.grid_blocks[i][j].usage);
VTR_LOG_ERROR("%d blocks were placed at grid location (%zu,%zu), but location capacity is %d.\n",
place_ctx.grid_blocks[i][j].usage, i, j, device_ctx.grid[i][j].type->capacity);
error++;
}
int usage_check = 0;
Expand Down Expand Up @@ -2674,16 +2674,16 @@ static int check_block_placement_consistency() {
bdone[bnum]++;
}
if (usage_check != place_ctx.grid_blocks[i][j].usage) {
VTR_LOG_ERROR("Location (%zu,%zu) usage is %d, but has actual usage %d.\n",
i, j, place_ctx.grid_blocks[i][j].usage, usage_check);
VTR_LOG_ERROR("%d block(s) were placed at location (%zu,%zu), but location contains %d block(s).\n",
place_ctx.grid_blocks[i][j].usage, i, j, usage_check);
error++;
}
}

/* Check that every block exists in the device_ctx.grid and cluster_ctx.blocks arrays somewhere. */
for (auto blk_id : cluster_ctx.clb_nlist.blocks())
if (bdone[blk_id] != 1) {
VTR_LOG_ERROR("Block %zu listed %d times in data structures.\n",
VTR_LOG_ERROR("Block %zu listed %d times in device context grid.\n",
size_t(blk_id), bdone[blk_id]);
error++;
}
Expand Down
147 changes: 147 additions & 0 deletions vpr/src/place/place_constraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "globals.h"
#include "place_constraints.h"
#include "place_util.h"

/*checks that each block's location is compatible with its floorplanning constraints if it has any*/
int check_placement_floorplanning() {
Expand Down Expand Up @@ -257,3 +258,149 @@ void load_cluster_constraints() {
}
}
}

void mark_fixed_blocks() {
auto& cluster_ctx = g_vpr_ctx.clustering();
auto& place_ctx = g_vpr_ctx.mutable_placement();
auto& floorplanning_ctx = g_vpr_ctx.floorplanning();

for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
if (!is_cluster_constrained(blk_id)) {
continue;
}
PartitionRegion pr = floorplanning_ctx.cluster_constraints[blk_id];
auto block_type = cluster_ctx.clb_nlist.block_type(blk_id);
t_pl_loc loc;

if (is_pr_size_one(pr, block_type, loc)) {
//Set block location and grid usage
set_block_location(blk_id, loc);

//Set as fixed
place_ctx.block_locs[blk_id].is_fixed = true;
}
}
}

/*
* Returns 0, 1, or 2 depending on the number of tiles covered.
* Will not return a value above 2 because as soon as num_tiles is above 1,
* it is known that the block that is assigned to this region will not be fixed, and so
* num_tiles is immediately returned.
* Updates the location passed in because if num_tiles turns out to be 1 after checking the
* region, the location that was set will be used as the location to which the block
* will be fixed.
*/
int region_tile_cover(const Region& reg, t_logical_block_type_ptr block_type, t_pl_loc& loc) {
auto& device_ctx = g_vpr_ctx.device();
vtr::Rect<int> rb = reg.get_region_rect();
int num_tiles = 0;

for (int x = rb.xmin(); x <= rb.xmax(); x++) {
for (int y = rb.ymin(); y <= rb.ymax(); y++) {
auto& tile = device_ctx.grid[x][y].type;

/*
* If the tile at the grid location is not compatible with the cluster block
* type, do not count this tile for num_tiles
*/
if (!is_tile_compatible(tile, block_type)) {
continue;
}

/*
* If the region passed has a specific subtile set, increment
* the number of tiles set the location using the x, y, subtile
* values
*/
if (reg.get_sub_tile() != NO_SUBTILE) {
num_tiles++;
loc.x = x;
loc.y = y;
loc.sub_tile = reg.get_sub_tile();
if (num_tiles > 1) {
return num_tiles;
}

/*
* If the region passed does not have a subtile set, set the
* subtile to zero. The loc that is set will only be used in the
* event that num_tiles is 1, and num_tiles will only be 1 if the
* capacity of the tile type turns out to be zero, thus implying
* that the location subtile will be zero.
*/
} else if (reg.get_sub_tile() == NO_SUBTILE) {
auto& cap = tile->capacity;
for (int z = 0; z < cap; z++) {
num_tiles++;
loc.x = x;
loc.y = y;
loc.sub_tile = 0;
if (num_tiles > 1) {
return num_tiles;
}
}
}
}
}

return num_tiles;
}

/*
* Used when marking fixed blocks to check whether the ParitionRegion associated with a block
* covers one tile. If it covers one tile, it is marked as fixed. If it covers 0 tiles or
* more than one tile, it will not be marked as fixed. As soon as it is known that the
* PartitionRegion covers more than one tile, there is no need to check further regions
* and the routine will return false.
*/
bool is_pr_size_one(PartitionRegion& pr, t_logical_block_type_ptr block_type, t_pl_loc& loc) {
std::vector<Region> regions = pr.get_partition_region();
bool pr_size_one;
Region intersect_reg;
int pr_size = 0;
int reg_size;

for (unsigned int i = 0; i < regions.size(); i++) {
reg_size = region_tile_cover(regions[i], block_type, loc);

/*
* If multiple regions in the PartitionRegion all have size 1,
* the block may still be marked as locked, in the case that
* they all cover the exact same tile. To check whether this
* is the case, whenever there is a size 1 region, it is intersected
* with the previous size 1 regions to see whether it covers the same tile.
* If there is an intersection, it does cover the same tile, and so pr_size is
* not incremented (unless this is the first size 1 region encountered).
*/
if (reg_size == 1) {
if (i == 0) {
intersect_reg = regions[0];
pr_size = pr_size + reg_size;
} else {
intersect_reg = intersection(intersect_reg, regions[i]);
}
if (intersect_reg.empty()) {
pr_size = pr_size + reg_size;
if (pr_size > 1) {
break;
}
} else {
continue;
}
}

pr_size = pr_size + reg_size;
if (pr_size > 1) {
break;
}
}

if (pr_size == 1) {
pr_size_one = true;
} else { //pr_size = 0 or pr_size > 1
pr_size_one = false;
}

return pr_size_one;
}
23 changes: 23 additions & 0 deletions vpr/src/place/place_constraints.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,27 @@ inline bool floorplan_legal(const t_pl_blocks_to_be_moved& blocks_affected) {
*/
void load_cluster_constraints();

/*
* Marks blocks as fixed if they have a constraint region that specifies exactly one x, y,
* subtile location as legal.
* Marking them as fixed indicates that they cannot be moved during initial placement and simulated annealing
*/
void mark_fixed_blocks();

/*
* Returns the number of tiles covered by a floorplan region.
* The return value of this routine will either be 0, 1, or 2. This
* is because this routine is used to check whether the region covers no tile,
* one tile, or more than one tile, and so as soon as it is seen that the number of tiles
* covered is 2, no further information is needed.
*/
int region_tile_cover(const Region& reg, t_logical_block_type_ptr block_type, t_pl_loc& loc);

/*
* Returns whether the PartitionRegion covers no tiles, 1 tile, or more than 1 tile.
* Used to decide whether to mark a block with the .is_fixed flag based on its floorplan
* region.
*/
bool is_pr_size_one(PartitionRegion& pr, t_logical_block_type_ptr block_type, t_pl_loc& loc);

#endif /* VPR_SRC_PLACE_PLACE_CONSTRAINTS_H_ */
Loading