Skip to content

[AP] Full Legalizer #2752

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
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 37 additions & 6 deletions vpr/src/analytical_place/analytical_placement_flow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@
#include "analytical_placement_flow.h"
#include "ap_netlist.h"
#include "atom_netlist.h"
#include "full_legalizer.h"
#include "gen_ap_netlist_from_atoms.h"
#include "globals.h"
#include "partial_placement.h"
#include "prepack.h"
#include "user_place_constraints.h"
#include "vpr_context.h"
#include "vpr_error.h"
#include "vpr_types.h"
#include "vtr_assert.h"
#include "vtr_time.h"

void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
(void)vpr_setup;
// Start an overall timer for the Analytical Placement flow.
vtr::ScopedStartFinishTimer timer("Analytical Placement Flow");
vtr::ScopedStartFinishTimer timer("Analytical Placement");

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

// AP is currently under-construction. Fail gracefully just in case this
// is somehow being called.
VPR_FATAL_ERROR(VPR_ERROR_AP,
"Analytical Placement flow not implemented yet");
// Run the Global Placer
// For now, just put all the moveable blocks at the center of the device
// grid. This will be replaced later. This is just for testing.
PartialPlacement p_placement(ap_netlist);
const size_t device_width = device_ctx.grid.width();
const size_t device_height = device_ctx.grid.height();
double device_center_x = static_cast<double>(device_width) / 2.0;
double device_center_y = static_cast<double>(device_height) / 2.0;
for (APBlockId ap_blk_id : ap_netlist.blocks()) {
if (ap_netlist.block_mobility(ap_blk_id) != APBlockMobility::MOVEABLE)
continue;
// If the APBlock is moveable, put it on the center for the device.
p_placement.block_x_locs[ap_blk_id] = device_center_x;
p_placement.block_y_locs[ap_blk_id] = device_center_y;
}
VTR_ASSERT(p_placement.verify(ap_netlist,
device_width,
device_height,
device_ctx.grid.get_num_layers()));

// Run the Full Legalizer.
FullLegalizer full_legalizer(ap_netlist,
vpr_setup,
device_ctx.grid,
device_ctx.arch,
atom_nlist,
prepacker,
device_ctx.logical_block_types,
vpr_setup.PackerRRGraph,
device_ctx.arch->models,
device_ctx.arch->model_library,
vpr_setup.PackerOpts);
full_legalizer.legalize(p_placement);
}

397 changes: 397 additions & 0 deletions vpr/src/analytical_place/full_legalizer.cpp

Large diffs are not rendered by default.

110 changes: 110 additions & 0 deletions vpr/src/analytical_place/full_legalizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* @file
* @author Alex Singer
* @date September 2024
* @brief Defines the FullLegalizer class which takes a partial AP placement
* and generates a fully legal clustering and placement which can be
* routed by VTR.
*/

#pragma once

#include <vector>

// Forward declarations
class APNetlist;
class AtomNetlist;
class ClusteredNetlist;
class DeviceGrid;
class PartialPlacement;
class Prepacker;
struct t_arch;
struct t_lb_type_rr_node;
struct t_logical_block_type;
struct t_model;
struct t_packer_opts;
struct t_vpr_setup;

/**
* @brief The full legalizer in an AP flow
*
* Given a valid partial placement (of any level of legality), will produce a
* fully legal clustering and placement for use in the rest of the VTR flow.
*/
class FullLegalizer {
public:
/**
* @brief Constructor of the Full Legalizer class.
*
* Brings in all the necessary state here. This is the state needed from the
* AP Context. the Packer Context, and the Placer Context.
*/
FullLegalizer(const APNetlist& ap_netlist,
t_vpr_setup& vpr_setup,
const DeviceGrid& device_grid,
const t_arch* arch,
const AtomNetlist& atom_netlist,
const Prepacker& prepacker,
const std::vector<t_logical_block_type>& logical_block_types,
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
const t_model* user_models,
const t_model* library_models,
const t_packer_opts& packer_opts)
: ap_netlist_(ap_netlist),
vpr_setup_(vpr_setup),
device_grid_(device_grid),
arch_(arch),
atom_netlist_(atom_netlist),
prepacker_(prepacker),
logical_block_types_(logical_block_types),
lb_type_rr_graphs_(lb_type_rr_graphs),
user_models_(user_models),
library_models_(library_models),
packer_opts_(packer_opts) {}

/**
* @brief Perform legalization on the given partial placement solution
*
* @param p_placement A valid partial placement (passes verify method).
* This implies that all blocks are placed on the
* device grid and fixed blocks are observed.
*/
void legalize(const PartialPlacement& p_placement);

private:
/**
* @brief Helper method to create the clusters from the given partial
* placement.
* TODO: Should return a ClusteredNetlist object, but need to wait until
* it is separated from load_cluster_constraints.
*/
void create_clusters(const PartialPlacement& p_placement);

/**
* @brief Helper method to place the clusters based on the given partial
* placement.
*/
void place_clusters(const ClusteredNetlist& clb_nlist,
const PartialPlacement& p_placement);

// AP Context Info
const APNetlist& ap_netlist_;
// Overall Setup Info
// FIXME: I do not like bringing all of this in. Perhaps clean up the methods
// that use it.
t_vpr_setup& vpr_setup_;
// Device Context Info
const DeviceGrid& device_grid_;
const t_arch* arch_;
// Packing Context Info
const AtomNetlist& atom_netlist_;
const Prepacker& prepacker_;
const std::vector<t_logical_block_type>& logical_block_types_;
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs_;
const t_model* user_models_;
const t_model* library_models_;
const t_packer_opts& packer_opts_;
// Placement Context Info
// TODO: Populate this once the placer is cleaned up some.
};

8 changes: 4 additions & 4 deletions vpr/src/analytical_place/partial_placement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

bool PartialPlacement::verify_locs(const APNetlist& netlist,
size_t grid_width,
size_t grid_height) {
size_t grid_height) const {
// Make sure all of the loc values are there.
if (block_x_locs.size() != netlist.blocks().size())
return false;
Expand Down Expand Up @@ -43,7 +43,7 @@ bool PartialPlacement::verify_locs(const APNetlist& netlist,
}

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

bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) const {
// Make sure all of the sub tiles are there
if (block_sub_tiles.size() != netlist.blocks().size())
return false;
Expand All @@ -88,7 +88,7 @@ bool PartialPlacement::verify_sub_tiles(const APNetlist& netlist) {
bool PartialPlacement::verify(const APNetlist& netlist,
size_t grid_width,
size_t grid_height,
size_t grid_num_layers) {
size_t grid_num_layers) const {
// Check that all the other verify methods passed.
if (!verify_locs(netlist, grid_width, grid_height))
return false;
Expand Down
49 changes: 45 additions & 4 deletions vpr/src/analytical_place/partial_placement.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@

#pragma once

#include <cmath>
#include "ap_netlist.h"
#include "physical_types.h"
#include "vtr_vector.h"

/**
Expand Down Expand Up @@ -94,6 +96,44 @@ struct PartialPlacement {
}
}

/**
* @brief Get the location of the physical tile that contains the given
* AP block.
*
* VTR uses an integer grid. In AP, we consider a tile at (1,1) to be
* centered at (1.5,1.5). When converting from doubles back to integer
* tiles, we simply take the floor, so the tile above would receive all
* points from [(1,1) to (2,2)). When converting fixed blocks from the
* integral VPR grid to the AP locations, we should therefore add (0.5,0.5)
* to them so they are centered in their grid tiles (assuming the tiles are
* 1x1).
*
* FIXME: Ideally this should return an ID to the tile, not a location.
* This is important since there is a distinction between the two.
* We know a block will be at that tile, but it would not be at the
* corner of the block (likely it would be at the center).
*/
inline t_physical_tile_loc get_containing_tile_loc(APBlockId blk_id) const {
// We take the floor here since we want to know which tile contains this
// block. On a grid, if the block is located at x=0.99999, it would still
// be in the first tile. This is because we assume that the blocks will
// ultimately end up in the center of the tile, not at the top left
// corner of it. The physical tile loc is just a way of identifying that
// tile.
// TODO: This may be a bit more complicated than this. This assumes that
// all tiles are 1x1, but it could be the case that this is on
// the edge of a much larger block. In reality this should try
// to go into the tile where it is closest to the center. What
// is written here is not necessarily wrong, but it may put blocks
// which on are the edge of large blocks into the large blocks.
// However, this may not even matter if the partial legalizer is
// doing its job!
int tile_x_loc = std::floor(block_x_locs[blk_id]);
int tile_y_loc = std::floor(block_y_locs[blk_id]);
int tile_layer = std::floor(block_layer_nums[blk_id]);
return t_physical_tile_loc(tile_x_loc, tile_y_loc, tile_layer);
}

/**
* @brief Verify the block_x_locs and block_y_locs vectors
*
Expand All @@ -108,7 +148,7 @@ struct PartialPlacement {
*/
bool verify_locs(const APNetlist& netlist,
size_t grid_width,
size_t grid_height);
size_t grid_height) const;

/**
* @brief Verify the block_layer_nums vector
Expand All @@ -121,7 +161,8 @@ struct PartialPlacement {
* @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);
bool verify_layer_nums(const APNetlist& netlist,
size_t grid_num_layers) const;

/**
* @brief Verify the sub_tiles
Expand All @@ -131,7 +172,7 @@ struct PartialPlacement {
*
* @param netlist The APNetlist used to generate this placement
*/
bool verify_sub_tiles(const APNetlist& netlist);
bool verify_sub_tiles(const APNetlist& netlist) const;

/**
* @brief Verify the entire partial placement object
Expand All @@ -146,6 +187,6 @@ struct PartialPlacement {
bool verify(const APNetlist& netlist,
size_t grid_width,
size_t grid_height,
size_t grid_num_layers);
size_t grid_num_layers) const;
};

9 changes: 9 additions & 0 deletions vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
// TODO: Make this return a bool if the placement was successful or not.
run_analytical_placement_flow(vpr_setup);
}
// Print the placement generated by AP to a .place file.
auto& filename_opts = vpr_setup.FileNameOpts;
auto& cluster_ctx = g_vpr_ctx.clustering();
const auto& block_locs = g_vpr_ctx.placement().block_locs();
auto& placement_id = g_vpr_ctx.mutable_placement().placement_id;
placement_id = print_place(filename_opts.NetFile.c_str(),
cluster_ctx.clb_nlist.netlist_id().c_str(),
filename_opts.PlaceFile.c_str(),
block_locs);
}

bool is_flat = vpr_setup.RouterOpts.flat_routing;
Expand Down
26 changes: 24 additions & 2 deletions vpr/src/pack/cluster_legalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,27 @@
#include "vtr_vector.h"
#include "vtr_vector_map.h"

/**
* @brief Counts the total number of logic models that the architecture can
* implement.
*
* @param user_models A linked list of logic models.
* @return The total number of models in the linked list
*/
static size_t count_models(const t_model* user_models) {
if (user_models == nullptr)
return 0;

size_t n_models = 0;
const t_model* cur_model = user_models;
while (cur_model != nullptr) {
n_models++;
cur_model = cur_model->next;
}

return n_models;
}

/*
* @brief Gets the max cluster size that any logical block can have.
*
Expand Down Expand Up @@ -1636,7 +1657,8 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist,
const Prepacker& prepacker,
const std::vector<t_logical_block_type>& logical_block_types,
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
size_t num_models,
const t_model* user_models,
const t_model* library_models,
const std::vector<std::string>& target_external_pin_util_str,
const t_pack_high_fanout_thresholds& high_fanout_thresholds,
ClusterLegalizationStrategy cluster_legalization_strategy,
Expand All @@ -1661,7 +1683,7 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist,
// Get a reference to the rr graphs.
lb_type_rr_graphs_ = lb_type_rr_graphs;
// Get the number of models in the architecture.
num_models_ = num_models;
num_models_ = count_models(user_models) + count_models(library_models);
// Find all NoC router atoms.
std::vector<AtomBlockId> noc_atoms = find_noc_router_atoms(atom_netlist);
update_noc_reachability_partitions(noc_atoms,
Expand Down
11 changes: 6 additions & 5 deletions vpr/src/pack/cluster_legalizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ class ClusterLegalizer {
* different cluster types. A reference is stored
* in the class to be used to allocate and load
* the router data.
* @param num_models The total number of models in the architecture.
* This is the sum of the number of the user and
* library models. Used internally to allocate data
* structures.
* @param user_models A linked list of the user models. Used to allocate
* an internal structure.
* @param library_models A linked list of the library models. Used to
* allocate an internal structure.
* @param target_external_pin_util_str A string used to initialize the
* target external pin utilization of
* each cluster type.
Expand Down Expand Up @@ -246,7 +246,8 @@ class ClusterLegalizer {
const Prepacker& prepacker,
const std::vector<t_logical_block_type>& logical_block_types,
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
size_t num_models,
const t_model* user_models,
const t_model* library_models,
const std::vector<std::string>& target_external_pin_util_str,
const t_pack_high_fanout_thresholds& high_fanout_thresholds,
ClusterLegalizationStrategy cluster_legalization_strategy,
Expand Down
Loading
Loading