-
Notifications
You must be signed in to change notification settings - Fork 414
[AP] Added Partial Placement Object #2742
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
vaughnbetz
merged 1 commit into
verilog-to-routing:master
from
AlexandreSinger:feature-ap-partial-placement-upstreaming
Sep 27, 2024
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/** | ||
* @file | ||
* @author Alex Singer | ||
* @date September 2024 | ||
* @brief The definitions of the PartialPlacement methods | ||
*/ | ||
|
||
#include "partial_placement.h" | ||
#include <cmath> | ||
#include <cstddef> | ||
#include "ap_netlist.h" | ||
|
||
bool PartialPlacement::verify_locs(const APNetlist& netlist, | ||
size_t grid_width, | ||
size_t grid_height) { | ||
// Make sure all of the loc values are there. | ||
if (block_x_locs.size() != netlist.blocks().size()) | ||
return false; | ||
if (block_y_locs.size() != netlist.blocks().size()) | ||
return false; | ||
// Make sure all locs are on the device and fixed locs are correct | ||
for (APBlockId blk_id : netlist.blocks()) { | ||
double x_pos = block_x_locs[blk_id]; | ||
double y_pos = block_y_locs[blk_id]; | ||
if (std::isnan(x_pos) || | ||
x_pos < 0.0 || | ||
x_pos >= grid_width) | ||
return false; | ||
if (std::isnan(y_pos) || | ||
y_pos < 0.0 || | ||
y_pos >= grid_height) | ||
return false; | ||
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) { | ||
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id); | ||
if (fixed_loc.x != -1 && x_pos != fixed_loc.x) | ||
return false; | ||
if (fixed_loc.y != -1 && y_pos != fixed_loc.y) | ||
return false; | ||
} | ||
} | ||
// If all previous checks passed, return true | ||
return true; | ||
} | ||
|
||
bool PartialPlacement::verify_layer_nums(const APNetlist& netlist, | ||
size_t grid_num_layers) { | ||
// Make sure all of the layer nums are there | ||
if (block_layer_nums.size() != netlist.blocks().size()) | ||
return false; | ||
// Make sure all layer_nums are on the device and fixed locs are correct. | ||
for (APBlockId blk_id : netlist.blocks()) { | ||
double layer_num = block_layer_nums[blk_id]; | ||
if (layer_num < 0.0 || layer_num >= static_cast<double>(grid_num_layers)) | ||
return false; | ||
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) { | ||
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id); | ||
if (fixed_loc.layer_num != -1 && layer_num != fixed_loc.layer_num) | ||
return false; | ||
} | ||
} | ||
// If all previous checks passed, return true | ||
return true; | ||
} | ||
|
||
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) { | ||
// Make sure all of the sub tiles are there | ||
if (block_sub_tiles.size() != netlist.blocks().size()) | ||
return false; | ||
// For now, we do not really do much with the sub_tile information. Ideally | ||
// we should check that all blocks have a sub_tile that actually exists | ||
// (a tile actually has a sub_tile of that idx); however, this may be | ||
// challenging to enforce. For now, just ensure that the number is | ||
// non-negative (implying a choice was made). | ||
for (APBlockId blk_id : netlist.blocks()) { | ||
int sub_tile = block_sub_tiles[blk_id]; | ||
if (sub_tile < 0) | ||
return false; | ||
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) { | ||
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id); | ||
if (fixed_loc.sub_tile != -1 && sub_tile != fixed_loc.sub_tile) | ||
return false; | ||
} | ||
} | ||
// If all previous checks passed, return true | ||
return true; | ||
} | ||
|
||
bool PartialPlacement::verify(const APNetlist& netlist, | ||
size_t grid_width, | ||
size_t grid_height, | ||
size_t grid_num_layers) { | ||
// Check that all the other verify methods passed. | ||
if (!verify_locs(netlist, grid_width, grid_height)) | ||
return false; | ||
if (!verify_layer_nums(netlist, grid_num_layers)) | ||
return false; | ||
if (!verify_sub_tiles(netlist)) | ||
return false; | ||
// If all other verify methods passed, then the placement is valid. | ||
return true; | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/** | ||
* @file | ||
* @author Alex Singer | ||
* @date September 2024 | ||
* @brief The declaration of the PartialPlacement object | ||
* | ||
* The partial placement object stores the placement of the APNetlist blocks | ||
* during different stages of the Analytical Placement flow. The Partial | ||
* Placement need not represent a legal placement; however, the placed blocks | ||
* will always be on the device and will respect fixed block locations. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "ap_netlist.h" | ||
#include "vtr_vector.h" | ||
|
||
/** | ||
* @brief A partial placement during the Analytical Placement flow | ||
* | ||
* The goal of this class is to contain positional information about the blocks | ||
* that gets passed around during analytical placement. | ||
* | ||
* The placement of a given APBlock is given by the following values: | ||
* - x_loc The x-position of the APBlock on the device grid | ||
* - y_loc The y-position of the APBlock on the device grid | ||
* - layer_num The layer on the device grid this block is on | ||
* - sub_tile The sub-tile this APBlock wants to be a part of | ||
* TODO: Not sure if we want to keep the sub tile, but it may be useful for | ||
* transferring information from the PartialLegalizer to the FullLegalizer. | ||
* | ||
* x_loc, y_loc, and layer_num are represented by doubles since APBlocks can be | ||
* placed in continuous space, rather than constrained to the integer device | ||
* grid of legal locations. These are doubles rather than floats since they | ||
* better fit the matrix solver we currently use. | ||
* | ||
* layer_num is represented by an int since it is not decided by an analytical | ||
* solver, but rather by the legalizers; so it does not need to be in continuous | ||
* space. | ||
* | ||
* This object assumes that the APNetlist object is static during the operation | ||
* of Analytical Placement (no blocks are added or removed). | ||
* | ||
* Note: The placement information was stored in this object as a struct of | ||
* arrays instead of an array of structs since it is assumed that the | ||
* main operations being performed on this placement will be analytical; | ||
* thus the x positions and y positions will likely be stored and computed | ||
* as separate continuous vectors. | ||
*/ | ||
struct PartialPlacement { | ||
/// @brief The x locations of all the APBlocks | ||
vtr::vector<APBlockId, double> block_x_locs; | ||
/// @brief The y locations of all the APBlocks | ||
vtr::vector<APBlockId, double> block_y_locs; | ||
/// @brief The layers of the device of all the APBlocks | ||
vtr::vector<APBlockId, double> block_layer_nums; | ||
/// @brief The sub tiles of all the APBlocks | ||
vtr::vector<APBlockId, int> block_sub_tiles; | ||
|
||
// Remove the default constructor. Need to construct this using an APNetlist. | ||
PartialPlacement() = delete; | ||
|
||
/** | ||
* @brief Construct the partial placement | ||
* | ||
* Uses the APNetlist object to allocate space for the locations of all | ||
* APBlocks. | ||
* | ||
* @param netlist The APNetlist which contains the blocks to be placed. | ||
*/ | ||
PartialPlacement(const APNetlist& netlist) | ||
: block_x_locs(netlist.blocks().size(), -1.0), | ||
block_y_locs(netlist.blocks().size(), -1.0), | ||
block_layer_nums(netlist.blocks().size(), 0.0), | ||
block_sub_tiles(netlist.blocks().size(), 0) { | ||
// Note: All blocks are initialized to: | ||
// x_loc = -1.0 | ||
// y_loc = -1.0 | ||
// layer_num = 0.0 | ||
// sub_tile = 0 | ||
// Load the fixed block locations | ||
for (APBlockId blk_id : netlist.blocks()) { | ||
if (netlist.block_mobility(blk_id) != APBlockMobility::FIXED) | ||
continue; | ||
const APFixedBlockLoc &loc = netlist.block_loc(blk_id); | ||
if (loc.x != -1) | ||
block_x_locs[blk_id] = loc.x; | ||
if (loc.y != -1) | ||
block_y_locs[blk_id] = loc.y; | ||
if (loc.layer_num != -1) | ||
block_layer_nums[blk_id] = loc.layer_num; | ||
if (loc.sub_tile != -1) | ||
block_sub_tiles[blk_id] = loc.sub_tile; | ||
AlexandreSinger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
/** | ||
* @brief Verify the block_x_locs and block_y_locs vectors | ||
* | ||
* Currently ensures: | ||
* - All blocks have locs | ||
* - All blocks are on the device | ||
* - All fixed locs are correct | ||
* | ||
* @param netlist The APNetlist used to generate this placement | ||
* @param grid_width The width of the device grid | ||
* @param grid_height The height of the device grid | ||
*/ | ||
bool verify_locs(const APNetlist& netlist, | ||
size_t grid_width, | ||
size_t grid_height); | ||
|
||
/** | ||
* @brief Verify the block_layer_nums vector | ||
* | ||
* Currently ensures: | ||
* - All blocks have layer_nums | ||
* - All blocks are on the device | ||
* - All fixed layers are correct | ||
* | ||
* @param netlist The APNetlist used to generate this placement | ||
* @param grid_num_layers The number of layers in the device grid | ||
*/ | ||
bool verify_layer_nums(const APNetlist& netlist, size_t grid_num_layers); | ||
|
||
/** | ||
* @brief Verify the sub_tiles | ||
* | ||
* Currently ensures: | ||
* - All sub_tiles are non-negative (implies unset) | ||
* | ||
* @param netlist The APNetlist used to generate this placement | ||
*/ | ||
bool verify_sub_tiles(const APNetlist& netlist); | ||
|
||
/** | ||
* @brief Verify the entire partial placement object | ||
* | ||
* Runs all of the verification checks above. | ||
* | ||
* @param netlist The APNetlist used to generate this placement | ||
* @param grid_width The width of the device grid | ||
* @param grid_height The height of the device grid | ||
* @param grid_num_layers The number of layers in the device grid | ||
*/ | ||
bool verify(const APNetlist& netlist, | ||
size_t grid_width, | ||
size_t grid_height, | ||
size_t grid_num_layers); | ||
}; | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/** | ||
* @file | ||
* @author Alex Singer | ||
* @date September 2024 | ||
* @brief Unit tests for the PartialPlacement object | ||
* | ||
* Very quick functionality checks to make sure that the methods inside of the | ||
* PartialPlacement object are working as expected. | ||
*/ | ||
|
||
#include "catch2/catch_test_macros.hpp" | ||
|
||
#include "ap_netlist.h" | ||
#include "partial_placement.h" | ||
#include "vpr_types.h" | ||
|
||
namespace { | ||
|
||
TEST_CASE("test_ap_partial_placement_verify", "[vpr_ap]") { | ||
// Create a test netlist object. | ||
APNetlist test_netlist("test_netlist"); | ||
// Create a few molecules. | ||
t_pack_molecule mol_a; | ||
t_pack_molecule mol_b; | ||
t_pack_molecule mol_c; | ||
// Create blocks for these molecules. | ||
APBlockId block_id_a = test_netlist.create_block("BlockA", &mol_a); | ||
APBlockId block_id_b = test_netlist.create_block("BlockB", &mol_b); | ||
APBlockId block_id_c = test_netlist.create_block("BlockC", &mol_c); | ||
// Fix BlockC. | ||
APFixedBlockLoc fixed_block_loc; | ||
fixed_block_loc.x = 12; | ||
fixed_block_loc.y = 42; | ||
fixed_block_loc.layer_num = 2; | ||
fixed_block_loc.sub_tile = 1; | ||
test_netlist.set_block_loc(block_id_c, fixed_block_loc); | ||
|
||
// Create the PartialPlacement object. | ||
PartialPlacement test_placement(test_netlist); | ||
|
||
SECTION("Test constructor places fixed blocks correctly") { | ||
REQUIRE(test_placement.block_x_locs[block_id_c] == fixed_block_loc.x); | ||
REQUIRE(test_placement.block_y_locs[block_id_c] == fixed_block_loc.y); | ||
REQUIRE(test_placement.block_layer_nums[block_id_c] == fixed_block_loc.layer_num); | ||
REQUIRE(test_placement.block_sub_tiles[block_id_c] == fixed_block_loc.sub_tile); | ||
} | ||
|
||
// Place the blocks | ||
// Place BlockA | ||
test_placement.block_x_locs[block_id_a] = 0; | ||
test_placement.block_y_locs[block_id_a] = 0; | ||
test_placement.block_layer_nums[block_id_a] = 0; | ||
test_placement.block_sub_tiles[block_id_a] = 0; | ||
// Place BlockB | ||
test_placement.block_x_locs[block_id_b] = 0; | ||
test_placement.block_y_locs[block_id_b] = 0; | ||
test_placement.block_layer_nums[block_id_b] = 0; | ||
test_placement.block_sub_tiles[block_id_b] = 0; | ||
|
||
SECTION("Test verify returns true when the placement is valid") { | ||
// NOTE: Using a very large device. | ||
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100)); | ||
// Picking sizes that just fit. | ||
REQUIRE(test_placement.verify(test_netlist, 13, 100, 100)); | ||
REQUIRE(test_placement.verify(test_netlist, 100, 43, 100)); | ||
REQUIRE(test_placement.verify(test_netlist, 100, 100, 3)); | ||
REQUIRE(test_placement.verify(test_netlist, 13, 43, 3)); | ||
} | ||
|
||
SECTION("Test verify methods all return true when verify returns true") { | ||
REQUIRE(test_placement.verify_locs(test_netlist, 100, 100)); | ||
REQUIRE(test_placement.verify_layer_nums(test_netlist, 100)); | ||
REQUIRE(test_placement.verify_sub_tiles(test_netlist)); | ||
} | ||
|
||
SECTION("Test verify returns false when blocks are outside grid") { | ||
// NOTE: Picking device sizes that are just small enough that BlockC | ||
// is off the device. | ||
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 1)); | ||
REQUIRE(!test_placement.verify_locs(test_netlist, 1, 100)); | ||
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 1)); | ||
// Make sure that the verify method also catches these cases | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 1, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 1, 100, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 1)); | ||
// Move BlockA off the grid into the negative direction | ||
test_placement.block_x_locs[block_id_a] = -1; | ||
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_x_locs[block_id_a] = 0; | ||
test_placement.block_y_locs[block_id_a] = -1; | ||
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_y_locs[block_id_a] = 0; | ||
test_placement.block_layer_nums[block_id_a] = -1; | ||
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_layer_nums[block_id_a] = 0; | ||
test_placement.block_sub_tiles[block_id_a] = -1; | ||
REQUIRE(!test_placement.verify_sub_tiles(test_netlist)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_sub_tiles[block_id_a] = 0; | ||
// Make sure everything is valid again | ||
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100)); | ||
} | ||
|
||
SECTION("Test verify returns false when fixed blocks are moved") { | ||
// Move BlockC's x-coordinate | ||
test_placement.block_x_locs[block_id_c] = 0; | ||
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_x_locs[block_id_c] = fixed_block_loc.x; | ||
// Move BlockC's y-coordinate | ||
test_placement.block_y_locs[block_id_c] = 0; | ||
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_y_locs[block_id_c] = fixed_block_loc.y; | ||
// Move BlockC's layer num | ||
test_placement.block_layer_nums[block_id_c] = 0; | ||
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 100)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_layer_nums[block_id_c] = fixed_block_loc.layer_num; | ||
// Move BlockC's sub tile | ||
test_placement.block_sub_tiles[block_id_c] = 0; | ||
REQUIRE(!test_placement.verify_sub_tiles(test_netlist)); | ||
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100)); | ||
test_placement.block_sub_tiles[block_id_c] = fixed_block_loc.sub_tile; | ||
// Make sure everything was put back correctly. | ||
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100)); | ||
} | ||
} | ||
|
||
} // namespace | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.