Skip to content

Commit a21ddbb

Browse files
[AP] Full Legalizer
The Full Legalizer in the AP flow takes a partial placement (of any legality) and returns a fully legal placement. A legal placement is a set of legal clusterers of atoms and legal places for those clusters to be placed. To fully test the AP flow, made a temporary Global Placer which will just place the APBlocks at the center of the device. This will be fixed later. Also includes basic tests to ensure the AP flow does not regress.
1 parent 3e53a93 commit a21ddbb

33 files changed

+2283
-58
lines changed

vpr/src/analytical_place/analytical_placement_flow.cpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@
88
#include "analytical_placement_flow.h"
99
#include "ap_netlist.h"
1010
#include "atom_netlist.h"
11+
#include "full_legalizer.h"
1112
#include "gen_ap_netlist_from_atoms.h"
1213
#include "globals.h"
14+
#include "partial_placement.h"
1315
#include "prepack.h"
1416
#include "user_place_constraints.h"
1517
#include "vpr_context.h"
16-
#include "vpr_error.h"
1718
#include "vpr_types.h"
19+
#include "vtr_assert.h"
1820
#include "vtr_time.h"
1921

2022
void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
2123
(void)vpr_setup;
2224
// Start an overall timer for the Analytical Placement flow.
23-
vtr::ScopedStartFinishTimer timer("Analytical Placement Flow");
25+
vtr::ScopedStartFinishTimer timer("Analytical Placement");
2426

2527
// The global state used/modified by this flow.
2628
const AtomNetlist& atom_nlist = g_vpr_ctx.atom().nlist;
@@ -37,9 +39,38 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
3739
prepacker,
3840
constraints);
3941

40-
// AP is currently under-construction. Fail gracefully just in case this
41-
// is somehow being called.
42-
VPR_FATAL_ERROR(VPR_ERROR_AP,
43-
"Analytical Placement flow not implemented yet");
42+
// Run the Global Placer
43+
// For now, just put all the moveable blocks at the center of the device
44+
// grid. This will be replaced later. This is just for testing.
45+
PartialPlacement p_placement(ap_netlist);
46+
const size_t device_width = device_ctx.grid.width();
47+
const size_t device_height = device_ctx.grid.height();
48+
double device_center_x = static_cast<double>(device_width) / 2.0;
49+
double device_center_y = static_cast<double>(device_height) / 2.0;
50+
for (APBlockId ap_blk_id : ap_netlist.blocks()) {
51+
if (ap_netlist.block_mobility(ap_blk_id) != APBlockMobility::MOVEABLE)
52+
continue;
53+
// If the APBlock is moveable, put it on the center for the device.
54+
p_placement.block_x_locs[ap_blk_id] = device_center_x;
55+
p_placement.block_y_locs[ap_blk_id] = device_center_y;
56+
}
57+
VTR_ASSERT(p_placement.verify(ap_netlist,
58+
device_width,
59+
device_height,
60+
device_ctx.grid.get_num_layers()));
61+
62+
// Run the Full Legalizer.
63+
FullLegalizer full_legalizer(ap_netlist,
64+
vpr_setup,
65+
device_ctx.grid,
66+
device_ctx.arch,
67+
atom_nlist,
68+
prepacker,
69+
device_ctx.logical_block_types,
70+
vpr_setup.PackerRRGraph,
71+
device_ctx.arch->models,
72+
device_ctx.arch->model_library,
73+
vpr_setup.PackerOpts);
74+
full_legalizer.legalize(p_placement);
4475
}
4576

vpr/src/analytical_place/full_legalizer.cpp

Lines changed: 397 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief Defines the FullLegalizer class which takes a partial AP placement
6+
* and generates a fully legal clustering and placement which can be
7+
* routed by VTR.
8+
*/
9+
10+
#pragma once
11+
12+
#include <vector>
13+
14+
// Forward declarations
15+
class APNetlist;
16+
class AtomNetlist;
17+
class ClusteredNetlist;
18+
class DeviceGrid;
19+
class PartialPlacement;
20+
class Prepacker;
21+
struct t_arch;
22+
struct t_lb_type_rr_node;
23+
struct t_logical_block_type;
24+
struct t_model;
25+
struct t_packer_opts;
26+
struct t_vpr_setup;
27+
28+
/**
29+
* @brief The full legalizer in an AP flow
30+
*
31+
* Given a valid partial placement (of any level of legality), will produce a
32+
* fully legal clustering and placement for use in the rest of the VTR flow.
33+
*/
34+
class FullLegalizer {
35+
public:
36+
/**
37+
* @brief Constructor of the Full Legalizer class.
38+
*
39+
* Brings in all the necessary state here. This is the state needed from the
40+
* AP Context. the Packer Context, and the Placer Context.
41+
*/
42+
FullLegalizer(const APNetlist& ap_netlist,
43+
t_vpr_setup& vpr_setup,
44+
const DeviceGrid& device_grid,
45+
const t_arch* arch,
46+
const AtomNetlist& atom_netlist,
47+
const Prepacker& prepacker,
48+
const std::vector<t_logical_block_type>& logical_block_types,
49+
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
50+
const t_model* user_models,
51+
const t_model* library_models,
52+
const t_packer_opts& packer_opts)
53+
: ap_netlist_(ap_netlist),
54+
vpr_setup_(vpr_setup),
55+
device_grid_(device_grid),
56+
arch_(arch),
57+
atom_netlist_(atom_netlist),
58+
prepacker_(prepacker),
59+
logical_block_types_(logical_block_types),
60+
lb_type_rr_graphs_(lb_type_rr_graphs),
61+
user_models_(user_models),
62+
library_models_(library_models),
63+
packer_opts_(packer_opts) {}
64+
65+
/**
66+
* @brief Perform legalization on the given partial placement solution
67+
*
68+
* @param p_placement A valid partial placement (passes verify method).
69+
* This implies that all blocks are placed on the
70+
* device grid and fixed blocks are observed.
71+
*/
72+
void legalize(const PartialPlacement& p_placement);
73+
74+
private:
75+
/**
76+
* @brief Helper method to create the clusters from the given partial
77+
* placement.
78+
* TODO: Should return a ClusteredNetlist object, but need to wait until
79+
* it is separated from load_cluster_constraints.
80+
*/
81+
void create_clusters(const PartialPlacement& p_placement);
82+
83+
/**
84+
* @brief Helper method to place the clusters based on the given partial
85+
* placement.
86+
*/
87+
void place_clusters(const ClusteredNetlist& clb_nlist,
88+
const PartialPlacement& p_placement);
89+
90+
// AP Context Info
91+
const APNetlist& ap_netlist_;
92+
// Overall Setup Info
93+
// FIXME: I do not like bringing all of this in. Perhaps clean up the methods
94+
// that use it.
95+
t_vpr_setup& vpr_setup_;
96+
// Device Context Info
97+
const DeviceGrid& device_grid_;
98+
const t_arch* arch_;
99+
// Packing Context Info
100+
const AtomNetlist& atom_netlist_;
101+
const Prepacker& prepacker_;
102+
const std::vector<t_logical_block_type>& logical_block_types_;
103+
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs_;
104+
const t_model* user_models_;
105+
const t_model* library_models_;
106+
const t_packer_opts& packer_opts_;
107+
// Placement Context Info
108+
// TODO: Populate this once the placer is cleaned up some.
109+
};
110+

vpr/src/analytical_place/partial_placement.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
bool PartialPlacement::verify_locs(const APNetlist& netlist,
1414
size_t grid_width,
15-
size_t grid_height) {
15+
size_t grid_height) const {
1616
// Make sure all of the loc values are there.
1717
if (block_x_locs.size() != netlist.blocks().size())
1818
return false;
@@ -43,7 +43,7 @@ bool PartialPlacement::verify_locs(const APNetlist& netlist,
4343
}
4444

4545
bool PartialPlacement::verify_layer_nums(const APNetlist& netlist,
46-
size_t grid_num_layers) {
46+
size_t grid_num_layers) const {
4747
// Make sure all of the layer nums are there
4848
if (block_layer_nums.size() != netlist.blocks().size())
4949
return false;
@@ -62,7 +62,7 @@ bool PartialPlacement::verify_layer_nums(const APNetlist& netlist,
6262
return true;
6363
}
6464

65-
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
65+
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) const {
6666
// Make sure all of the sub tiles are there
6767
if (block_sub_tiles.size() != netlist.blocks().size())
6868
return false;
@@ -88,7 +88,7 @@ bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
8888
bool PartialPlacement::verify(const APNetlist& netlist,
8989
size_t grid_width,
9090
size_t grid_height,
91-
size_t grid_num_layers) {
91+
size_t grid_num_layers) const {
9292
// Check that all the other verify methods passed.
9393
if (!verify_locs(netlist, grid_width, grid_height))
9494
return false;

vpr/src/analytical_place/partial_placement.h

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
#pragma once
1414

15+
#include <cmath>
1516
#include "ap_netlist.h"
17+
#include "physical_types.h"
1618
#include "vtr_vector.h"
1719

1820
/**
@@ -94,6 +96,35 @@ struct PartialPlacement {
9496
}
9597
}
9698

99+
/**
100+
* @brief Get the location of the physical tile that contains the given
101+
* AP block.
102+
* FIXME: Ideally this should return an ID to the tile, not a location.
103+
* This is important since there is a distinction between the two.
104+
* We know a block will be at that tile, but it would not be at the
105+
* corner of the block (likely it would be at the center).
106+
*/
107+
inline t_physical_tile_loc get_containing_tile_loc(APBlockId blk_id) const {
108+
// We take the floor here since we want to know which tile contains this
109+
// block. On a grid, if the block is located at x=0.99999, it would still
110+
// be in the first tile. This is because we assume that the blocks will
111+
// ultimately end up in the center of the tile, not at the top left
112+
// corner of it. The physical tile loc is just a way of identifying that
113+
// tile.
114+
// TODO: This may be a bit more complicated than this. This assumes that
115+
// all tiles are 1x1, but it could be the case that this is on
116+
// the edge of a much larger block. In reality this should try
117+
// to go into the tile where it is closest to the center. What
118+
// is written here is not necessarily wrong, but it may put blocks
119+
// which on are the edge of large blocks into the large blocks.
120+
// However, this may not even matter if the partial legalizer is
121+
// doing its job!
122+
int tile_x_loc = std::floor(block_x_locs[blk_id]);
123+
int tile_y_loc = std::floor(block_y_locs[blk_id]);
124+
int tile_layer = std::floor(block_layer_nums[blk_id]);
125+
return t_physical_tile_loc(tile_x_loc, tile_y_loc, tile_layer);
126+
}
127+
97128
/**
98129
* @brief Verify the block_x_locs and block_y_locs vectors
99130
*
@@ -108,7 +139,7 @@ struct PartialPlacement {
108139
*/
109140
bool verify_locs(const APNetlist& netlist,
110141
size_t grid_width,
111-
size_t grid_height);
142+
size_t grid_height) const;
112143

113144
/**
114145
* @brief Verify the block_layer_nums vector
@@ -121,7 +152,8 @@ struct PartialPlacement {
121152
* @param netlist The APNetlist used to generate this placement
122153
* @param grid_num_layers The number of layers in the device grid
123154
*/
124-
bool verify_layer_nums(const APNetlist& netlist, size_t grid_num_layers);
155+
bool verify_layer_nums(const APNetlist& netlist,
156+
size_t grid_num_layers) const;
125157

126158
/**
127159
* @brief Verify the sub_tiles
@@ -131,7 +163,7 @@ struct PartialPlacement {
131163
*
132164
* @param netlist The APNetlist used to generate this placement
133165
*/
134-
bool verify_sub_tiles(const APNetlist& netlist);
166+
bool verify_sub_tiles(const APNetlist& netlist) const;
135167

136168
/**
137169
* @brief Verify the entire partial placement object
@@ -146,6 +178,6 @@ struct PartialPlacement {
146178
bool verify(const APNetlist& netlist,
147179
size_t grid_width,
148180
size_t grid_height,
149-
size_t grid_num_layers);
181+
size_t grid_num_layers) const;
150182
};
151183

vpr/src/base/vpr_api.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,15 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
411411
// TODO: Make this return a bool if the placement was successful or not.
412412
run_analytical_placement_flow(vpr_setup);
413413
}
414+
// Print the placement generated by AP to a .place file.
415+
auto& filename_opts = vpr_setup.FileNameOpts;
416+
auto& cluster_ctx = g_vpr_ctx.clustering();
417+
const auto& block_locs = g_vpr_ctx.placement().block_locs();
418+
auto& placement_id = g_vpr_ctx.mutable_placement().placement_id;
419+
placement_id = print_place(filename_opts.NetFile.c_str(),
420+
cluster_ctx.clb_nlist.netlist_id().c_str(),
421+
filename_opts.PlaceFile.c_str(),
422+
block_locs);
414423
}
415424

416425
bool is_flat = vpr_setup.RouterOpts.flat_routing;

vpr/src/pack/cluster_legalizer.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,27 @@
3838
#include "vtr_vector.h"
3939
#include "vtr_vector_map.h"
4040

41+
/**
42+
* @brief Counts the total number of logic models that the architecture can
43+
* implement.
44+
*
45+
* @param user_models A linked list of logic models.
46+
* @return The total number of models in the linked list
47+
*/
48+
static size_t count_models(const t_model* user_models) {
49+
if (user_models == nullptr)
50+
return 0;
51+
52+
size_t n_models = 0;
53+
const t_model* cur_model = user_models;
54+
while (cur_model != nullptr) {
55+
n_models++;
56+
cur_model = cur_model->next;
57+
}
58+
59+
return n_models;
60+
}
61+
4162
/*
4263
* @brief Gets the max cluster size that any logical block can have.
4364
*
@@ -1636,7 +1657,8 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist,
16361657
const Prepacker& prepacker,
16371658
const std::vector<t_logical_block_type>& logical_block_types,
16381659
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
1639-
size_t num_models,
1660+
const t_model* user_models,
1661+
const t_model* library_models,
16401662
const std::vector<std::string>& target_external_pin_util_str,
16411663
const t_pack_high_fanout_thresholds& high_fanout_thresholds,
16421664
ClusterLegalizationStrategy cluster_legalization_strategy,
@@ -1661,7 +1683,7 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist,
16611683
// Get a reference to the rr graphs.
16621684
lb_type_rr_graphs_ = lb_type_rr_graphs;
16631685
// Get the number of models in the architecture.
1664-
num_models_ = num_models;
1686+
num_models_ = count_models(user_models) + count_models(library_models);
16651687
// Find all NoC router atoms.
16661688
std::vector<AtomBlockId> noc_atoms = find_noc_router_atoms(atom_netlist);
16671689
update_noc_reachability_partitions(noc_atoms,

vpr/src/pack/cluster_legalizer.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ class ClusterLegalizer {
215215
* different cluster types. A reference is stored
216216
* in the class to be used to allocate and load
217217
* the router data.
218-
* @param num_models The total number of models in the architecture.
219-
* This is the sum of the number of the user and
220-
* library models. Used internally to allocate data
221-
* structures.
218+
* @param user_models A linked list of the user models. Used to allocate
219+
* an internal structure.
220+
* @param library_models A linked list of the library models. Used to
221+
* allocate an internal structure.
222222
* @param target_external_pin_util_str A string used to initialize the
223223
* target external pin utilization of
224224
* each cluster type.
@@ -246,7 +246,8 @@ class ClusterLegalizer {
246246
const Prepacker& prepacker,
247247
const std::vector<t_logical_block_type>& logical_block_types,
248248
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
249-
size_t num_models,
249+
const t_model* user_models,
250+
const t_model* library_models,
250251
const std::vector<std::string>& target_external_pin_util_str,
251252
const t_pack_high_fanout_thresholds& high_fanout_thresholds,
252253
ClusterLegalizationStrategy cluster_legalization_strategy,

0 commit comments

Comments
 (0)