Skip to content

Commit 9ffe1bf

Browse files
[AP] Added Partial Placement Object
Added the partial placement object. This object is used during the Analytical Placement flow to store the positions of the APBlocks. This placement is not gaurenteed to be legal; however, it does gaurentee that the blocks are placed on the device and the fixed blocks are placed in valid locations.
1 parent 13f37a6 commit 9ffe1bf

File tree

3 files changed

+378
-0
lines changed

3 files changed

+378
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief The definitions of the PartialPlacement methods
6+
*/
7+
8+
#include "partial_placement.h"
9+
#include <cmath>
10+
#include <cstddef>
11+
#include "ap_netlist.h"
12+
13+
bool PartialPlacement::verify_locs(const APNetlist& netlist,
14+
size_t grid_width,
15+
size_t grid_height) {
16+
// Make sure all of the loc values are there.
17+
if (block_x_locs.size() != netlist.blocks().size())
18+
return false;
19+
if (block_y_locs.size() != netlist.blocks().size())
20+
return false;
21+
// Make sure all locs are on the device and fixed locs are correct
22+
for (APBlockId blk_id : netlist.blocks()) {
23+
double x_pos = block_x_locs[blk_id];
24+
double y_pos = block_y_locs[blk_id];
25+
if (std::isnan(x_pos) ||
26+
x_pos < 0.0 ||
27+
x_pos >= grid_width)
28+
return false;
29+
if (std::isnan(y_pos) ||
30+
y_pos < 0.0 ||
31+
y_pos >= grid_height)
32+
return false;
33+
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) {
34+
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id);
35+
if (fixed_loc.x != -1 && x_pos != fixed_loc.x)
36+
return false;
37+
if (fixed_loc.y != -1 && y_pos != fixed_loc.y)
38+
return false;
39+
}
40+
}
41+
// If all previous checks passed, return true
42+
return true;
43+
}
44+
45+
bool PartialPlacement::verify_layer_nums(const APNetlist& netlist,
46+
size_t grid_num_layers) {
47+
// Make sure all of the layer nums are there
48+
if (block_layer_nums.size() != netlist.blocks().size())
49+
return false;
50+
// Make sure all layer_nums are on the device and fixed locs are correct.
51+
for (APBlockId blk_id : netlist.blocks()) {
52+
int layer_num = block_layer_nums[blk_id];
53+
if (layer_num < 0 || layer_num >= static_cast<int>(grid_num_layers))
54+
return false;
55+
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) {
56+
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id);
57+
if (fixed_loc.layer_num != -1 && layer_num != fixed_loc.layer_num)
58+
return false;
59+
}
60+
}
61+
// If all previous checks passed, return true
62+
return true;
63+
}
64+
65+
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
66+
// Make sure all of the sub tiles are there
67+
if (block_sub_tiles.size() != netlist.blocks().size())
68+
return false;
69+
// For now, we do not really do much with the sub_tile information. Ideally
70+
// we should check that all blocks have a sub_tile that actually exists
71+
// (a tile actually has a sub_tile of that idx); however, this may be
72+
// challenging to enforce. For now, just ensure that the number is
73+
// non-negative (implying a choice was made).
74+
for (APBlockId blk_id : netlist.blocks()) {
75+
int sub_tile = block_sub_tiles[blk_id];
76+
if (sub_tile < 0)
77+
return false;
78+
if (netlist.block_mobility(blk_id) == APBlockMobility::FIXED) {
79+
const APFixedBlockLoc& fixed_loc = netlist.block_loc(blk_id);
80+
if (fixed_loc.sub_tile != -1 && sub_tile != fixed_loc.sub_tile)
81+
return false;
82+
}
83+
}
84+
// If all previous checks passed, return true
85+
return true;
86+
}
87+
88+
bool PartialPlacement::verify(const APNetlist& netlist,
89+
size_t grid_width,
90+
size_t grid_height,
91+
size_t grid_num_layers) {
92+
// Check that all the other verify methods passed.
93+
if (!verify_locs(netlist, grid_width, grid_height))
94+
return false;
95+
if (!verify_layer_nums(netlist, grid_num_layers))
96+
return false;
97+
if (!verify_sub_tiles(netlist))
98+
return false;
99+
// If all other verify methods passed, then the placement is valid.
100+
return true;
101+
}
102+
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief The declaration of the PartialPlacement object
6+
*
7+
* The partial placement object stores the placement of the APNetlist blocks
8+
* during different stages of the Analytical Placement flow. The Partial
9+
* Placement need not represent a legal placement; however, the placed blocks
10+
* will always be on the device and will respect fixed block locations.
11+
*/
12+
13+
#pragma once
14+
15+
#include "ap_netlist.h"
16+
#include "vtr_vector.h"
17+
18+
/**
19+
* @brief A partial placement during the Analytical Placement flow
20+
*
21+
* The goal of this class is to contain positional information about the blocks
22+
* that gets passed around during analytical placement.
23+
*
24+
* The placement of a given APBlock is given by the following values:
25+
* - x_loc The x-position of the APBlock on the device grid
26+
* - y_loc The y-position of the APBlock on the device grid
27+
* - layer_num The layer on the device grid this block is on
28+
* - sub_tile The sub-tile this APBlock wants to be a part of
29+
* TODO: Not sure if we want to keep the sub tile, but it may be useful for
30+
* transferring information from the PartialLegalizer to the FullLegalizer.
31+
*
32+
* This object assumes that the APNetlist object is static during the operation
33+
* of Analytical Placement (no blocks are added or removed).
34+
*
35+
* Note: The placement information was stored in this object as a struct of
36+
* arrays instead of an array of structs since it is assumed that the
37+
* main operations being performed on this placement will be analytical;
38+
* thus the x positions and y positions will likely be stored and computed
39+
* as separate continuous vectors.
40+
*/
41+
struct PartialPlacement {
42+
/// @brief The x locations of all the APBlocks
43+
vtr::vector<APBlockId, double> block_x_locs;
44+
/// @brief The y locations of all the APBlocks
45+
vtr::vector<APBlockId, double> block_y_locs;
46+
/// @brief The layers of the device of all the APBlocks
47+
vtr::vector<APBlockId, int> block_layer_nums;
48+
/// @breif The sub tiles of all the APBlocks
49+
vtr::vector<APBlockId, int> block_sub_tiles;
50+
51+
// Remove the default constructor. Need to construct this using an APNetlist.
52+
PartialPlacement() = delete;
53+
54+
/**
55+
* @brief Construct the partial placement
56+
*
57+
* Uses the APNetlist object to allocate space for the locations of all
58+
* APBlocks.
59+
*
60+
* @param netlist The APNetlist which contains the blocks to be placed.
61+
*/
62+
PartialPlacement(const APNetlist& netlist)
63+
: block_x_locs(netlist.blocks().size(), -1.f),
64+
block_y_locs(netlist.blocks().size(), -1.f),
65+
block_layer_nums(netlist.blocks().size(), 0),
66+
block_sub_tiles(netlist.blocks().size(), 0) {
67+
// Note: All blocks are initialized to:
68+
// x_loc = -1.f
69+
// y_loc = -1.f
70+
// layer_num = 0
71+
// sub_tile = 0
72+
// Load the fixed block locations
73+
for (APBlockId blk_id : netlist.blocks()) {
74+
if (netlist.block_mobility(blk_id) != APBlockMobility::FIXED)
75+
continue;
76+
const APFixedBlockLoc &loc = netlist.block_loc(blk_id);
77+
if (loc.x != -1)
78+
block_x_locs[blk_id] = loc.x;
79+
if (loc.y != -1)
80+
block_y_locs[blk_id] = loc.y;
81+
if (loc.layer_num != -1)
82+
block_layer_nums[blk_id] = loc.layer_num;
83+
if (loc.sub_tile != -1)
84+
block_sub_tiles[blk_id] = loc.sub_tile;
85+
}
86+
}
87+
88+
/**
89+
* @brief Verify the block_x_locs and block_y_locs vectors
90+
*
91+
* Currently ensures:
92+
* - All blocks have locs
93+
* - All blocks are on the device
94+
* - All fixed locs are correct
95+
*
96+
* @param netlist The APNetlist used to generate this placement
97+
* @param grid_width The width of the device grid
98+
* @param grid_height The height of the device grid
99+
*/
100+
bool verify_locs(const APNetlist& netlist,
101+
size_t grid_width,
102+
size_t grid_height);
103+
104+
/**
105+
* @brief Verify the block_layer_nums vector
106+
*
107+
* Currently ensures:
108+
* - All blocks have layer_nums
109+
* - All blocks are on the device
110+
* - All fixed layers are correct
111+
*
112+
* @param netlist The APNetlist used to generate this placement
113+
* @param grid_num_layers The number of layers in the device grid
114+
*/
115+
bool verify_layer_nums(const APNetlist& netlist, size_t grid_num_layers);
116+
117+
/**
118+
* @brief Verify the sub_tiles
119+
*
120+
* Currently ensures:
121+
* - All sub_tiles are non-negative (implies unset)
122+
*
123+
* @param netlist The APNetlist used to generate this placement
124+
*/
125+
bool verify_sub_tiles(const APNetlist& netlist);
126+
127+
/**
128+
* @brief Verify the entire partial placement object
129+
*
130+
* Runs all of the verification checks above.
131+
*
132+
* @param netlist The APNetlist used to generate this placement
133+
* @param grid_width The width of the device grid
134+
* @param grid_height The height of the device grid
135+
* @param grid_num_layers The number of layers in the device grid
136+
*/
137+
bool verify(const APNetlist& netlist,
138+
size_t grid_width,
139+
size_t grid_height,
140+
size_t grid_num_layers);
141+
};
142+
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief Unit tests for the PartialPlacement object
6+
*
7+
* Very quick functionality checks to make sure that the methods inside of the
8+
* PartialPlacement object are working as expected.
9+
*/
10+
11+
#include "catch2/catch_test_macros.hpp"
12+
13+
#include "ap_netlist.h"
14+
#include "partial_placement.h"
15+
#include "vpr_types.h"
16+
17+
namespace {
18+
19+
TEST_CASE("test_ap_partial_placement_verify", "[vpr_ap]") {
20+
// Create a test netlist object.
21+
APNetlist test_netlist("test_netlist");
22+
// Create a few molecules.
23+
t_pack_molecule mol_a;
24+
t_pack_molecule mol_b;
25+
t_pack_molecule mol_c;
26+
// Create blocks for these molecules.
27+
APBlockId block_id_a = test_netlist.create_block("BlockA", &mol_a);
28+
APBlockId block_id_b = test_netlist.create_block("BlockB", &mol_b);
29+
APBlockId block_id_c = test_netlist.create_block("BlockC", &mol_c);
30+
// Fix BlockC.
31+
APFixedBlockLoc fixed_block_loc;
32+
fixed_block_loc.x = 12;
33+
fixed_block_loc.y = 42;
34+
fixed_block_loc.layer_num = 2;
35+
fixed_block_loc.sub_tile = 1;
36+
test_netlist.set_block_loc(block_id_c, fixed_block_loc);
37+
38+
// Create the PartialPlacement object.
39+
PartialPlacement test_placement(test_netlist);
40+
41+
SECTION("Test constructor places fixed blocks correctly") {
42+
REQUIRE(test_placement.block_x_locs[block_id_c] == fixed_block_loc.x);
43+
REQUIRE(test_placement.block_y_locs[block_id_c] == fixed_block_loc.y);
44+
REQUIRE(test_placement.block_layer_nums[block_id_c] == fixed_block_loc.layer_num);
45+
REQUIRE(test_placement.block_sub_tiles[block_id_c] == fixed_block_loc.sub_tile);
46+
}
47+
48+
// Place the blocks
49+
// Place BlockA
50+
test_placement.block_x_locs[block_id_a] = 0;
51+
test_placement.block_y_locs[block_id_a] = 0;
52+
test_placement.block_layer_nums[block_id_a] = 0;
53+
test_placement.block_sub_tiles[block_id_a] = 0;
54+
// Place BlockB
55+
test_placement.block_x_locs[block_id_b] = 0;
56+
test_placement.block_y_locs[block_id_b] = 0;
57+
test_placement.block_layer_nums[block_id_b] = 0;
58+
test_placement.block_sub_tiles[block_id_b] = 0;
59+
60+
SECTION("Test verify returns true when the placement is valid") {
61+
// NOTE: Using a very large device.
62+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100));
63+
// Picking sizes that just fit.
64+
REQUIRE(test_placement.verify(test_netlist, 13, 100, 100));
65+
REQUIRE(test_placement.verify(test_netlist, 100, 43, 100));
66+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 3));
67+
REQUIRE(test_placement.verify(test_netlist, 13, 43, 3));
68+
}
69+
70+
SECTION("Test verify methods all return true when verify returns true") {
71+
REQUIRE(test_placement.verify_locs(test_netlist, 100, 100));
72+
REQUIRE(test_placement.verify_layer_nums(test_netlist, 100));
73+
REQUIRE(test_placement.verify_sub_tiles(test_netlist));
74+
}
75+
76+
SECTION("Test verify returns false when blocks are outside grid") {
77+
// NOTE: Picking device sizes that are just small enough that BlockC
78+
// is off the device.
79+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 1));
80+
REQUIRE(!test_placement.verify_locs(test_netlist, 1, 100));
81+
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 1));
82+
// Make sure that the verify method also catches these cases
83+
REQUIRE(!test_placement.verify(test_netlist, 100, 1, 100));
84+
REQUIRE(!test_placement.verify(test_netlist, 1, 100, 100));
85+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 1));
86+
// Move BlockA off the grid into the negative direction
87+
test_placement.block_x_locs[block_id_a] = -1;
88+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
89+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
90+
test_placement.block_x_locs[block_id_a] = 0;
91+
test_placement.block_y_locs[block_id_a] = -1;
92+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
93+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
94+
test_placement.block_y_locs[block_id_a] = 0;
95+
test_placement.block_layer_nums[block_id_a] = -1;
96+
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 100));
97+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
98+
test_placement.block_layer_nums[block_id_a] = 0;
99+
test_placement.block_sub_tiles[block_id_a] = -1;
100+
REQUIRE(!test_placement.verify_sub_tiles(test_netlist));
101+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
102+
test_placement.block_sub_tiles[block_id_a] = 0;
103+
// Make sure everything is valid again
104+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100));
105+
}
106+
107+
SECTION("Test verify returns false when fixed blocks are moved") {
108+
// Move BlockC's x-coordinate
109+
test_placement.block_x_locs[block_id_c] = 0;
110+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
111+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
112+
test_placement.block_x_locs[block_id_c] = fixed_block_loc.x;
113+
// Move BlockC's y-coordinate
114+
test_placement.block_y_locs[block_id_c] = 0;
115+
REQUIRE(!test_placement.verify_locs(test_netlist, 100, 100));
116+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
117+
test_placement.block_y_locs[block_id_c] = fixed_block_loc.y;
118+
// Move BlockC's layer num
119+
test_placement.block_layer_nums[block_id_c] = 0;
120+
REQUIRE(!test_placement.verify_layer_nums(test_netlist, 100));
121+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
122+
test_placement.block_layer_nums[block_id_c] = fixed_block_loc.layer_num;
123+
// Move BlockC's sub tile
124+
test_placement.block_sub_tiles[block_id_c] = 0;
125+
REQUIRE(!test_placement.verify_sub_tiles(test_netlist));
126+
REQUIRE(!test_placement.verify(test_netlist, 100, 100, 100));
127+
test_placement.block_sub_tiles[block_id_c] = fixed_block_loc.sub_tile;
128+
// Make sure everything was put back correctly.
129+
REQUIRE(test_placement.verify(test_netlist, 100, 100, 100));
130+
}
131+
}
132+
133+
} // namespace
134+

0 commit comments

Comments
 (0)