Skip to content

Commit

Permalink
[AP] Added APPack to the AP Flow as a Full Legalizer
Browse files Browse the repository at this point in the history
APPack is a Full Legalizer which modifies the Packer and Placer to try
and improve their solutions based on a given Flat Placement. Integrated
this into the AP Flow by converting the Partial Placement generated by
the Global Placer into a Flat Placement and calling the Packer and
Placer.

Kept the original, Naive Full Legalizer as something to compare to and
since it may be useful to keep this legalizer around.

Added tests for both the Naive and APPack Full Legalizers, leaving the
other tests to always run on the default AP Flow.
  • Loading branch information
AlexandreSinger committed Feb 11, 2025
1 parent 0cf372a commit 25e2450
Show file tree
Hide file tree
Showing 20 changed files with 500 additions and 96 deletions.
38 changes: 37 additions & 1 deletion doc/src/vpr/command_line_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ VPR runs all stages of (pack, place, route, and analysis) if none of :option:`--
as such, the :option:`--pack` and :option:`--place` options should not be set when this option is set.
This flow requires that the device has a fixed size and some of the primitive blocks are fixed somewhere on the device grid.

.. seealso:: See :ref:`analytical_placement_options` for the options for this flow.

.. seealso:: See :ref:`Fixed FPGA Grid Layout <fixed_arch_grid_layout>` and :option:`--device` for how to fix the device size.

.. seealso:: See :ref:`VPR Placement Constraints <placement_constraints>` for how to fix primitive blocks in a design to the device grid.
Expand Down Expand Up @@ -1163,6 +1165,40 @@ The following options are only used when FPGA device and netlist contain a NoC r

**Default:** ``vpr_noc_placement_output.txt``


.. _analytical_placement_options:

Analytical Placement Options
^^^^^^^^^^^^^^^
Instead of Packing atoms into clusters and placing the clusters into valid tile
sites on the FPGA, Analytical Placement uses analytical techniques to place atoms
on the FPGA device by relaxing the constraints on where they can be placed. This
atom-level placement is then legalized into a clustered placement and passed into
the router in VPR.

Analytical Placement is generally split into three stages:

* Global Placement: Uses analytical techniques to place atoms on the FPGA grid.

* Full Legalization: Legalizes a flat (atom) placement into legal clusters placed on the FPGA grid.

* Detailed Placement: While keeping the clusters legal, performs optimizations on the clustered placement.

.. warning::

Analytical Placement is experimental and under active development.

.. option:: --ap_full_legalizer {naive | appack}

Controls which Full Legalizer to use in the AP Flow.

* ``naive`` Use a Naive Full Legalizer which will try to create clusters exactly where their atoms are placed.

* ``appack`` Use APPack, which takes the Packer in VPR and uses the flat atom placement to create better clusters.

**Default:** ``appack``


.. _router_options:

Router Options
Expand All @@ -1179,7 +1215,7 @@ VPR uses a negotiated congestion algorithm (based on Pathfinder) to perform rout
This means that during the routing stage, all nets, both intra- and inter-cluster, are routed directly from one primitive pin to another primitive pin.
This increases routing time but can improve routing quality by re-arranging LUT inputs and exposing additional optimization opportunities in architectures with local intra-cluster routing that is not a full crossbar.

**Default:** ``OFF`
**Default:** ``off``

.. option:: --max_router_iterations <int>

Expand Down
22 changes: 10 additions & 12 deletions vpr/src/analytical_place/analytical_placement_flow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,15 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
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);
const t_ap_opts& ap_opts = vpr_setup.APOpts;
std::unique_ptr<FullLegalizer> full_legalizer = make_full_legalizer(ap_opts.full_legalizer_type,
ap_netlist,
atom_nlist,
prepacker,
vpr_setup,
*device_ctx.arch,
device_ctx.grid,
device_ctx.logical_block_types);
full_legalizer->legalize(p_placement);
}

20 changes: 20 additions & 0 deletions vpr/src/analytical_place/ap_flow_enums.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @file
* @author Alex Singer
* @date February 2025
* @brief Enumerations used by the Analytical Placement Flow.
*/

#pragma once

/**
* @brief The type of a Full Legalizer.
*
* The Analytical Placement flow may implement different Full Legalizers. This
* enum can select between these different Full Legalizers.
*/
enum class e_ap_full_legalizer {
Naive, ///< The Naive Full Legalizer, which clusters atoms placed in the same tile and tries to place them in that tile according to the flat placement.
APPack ///< The APPack Full Legalizer, which uses the flat placement to improve the Packer and Placer.
};

129 changes: 114 additions & 15 deletions vpr/src/analytical_place/full_legalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
#include "full_legalizer.h"

#include <list>
#include <memory>
#include <unordered_set>
#include <vector>

#include "FlatPlacementInfo.h"
#include "ap_flow_enums.h"
#include "device_grid.h"
#include "partial_placement.h"
#include "ShowSetup.h"
#include "ap_netlist_fwd.h"
Expand All @@ -25,6 +29,7 @@
#include "logic_types.h"
#include "pack.h"
#include "physical_types.h"
#include "place.h"
#include "place_and_route.h"
#include "place_constraints.h"
#include "place_macro.h"
Expand All @@ -42,6 +47,38 @@
#include "vtr_time.h"
#include "vtr_vector.h"


std::unique_ptr<FullLegalizer> make_full_legalizer(e_ap_full_legalizer full_legalizer_type,
const APNetlist& ap_netlist,
const AtomNetlist& atom_netlist,
const Prepacker& prepacker,
t_vpr_setup& vpr_setup,
const t_arch& arch,
const DeviceGrid& device_grid,
const std::vector<t_logical_block_type>& logical_block_types) {
switch (full_legalizer_type) {
case e_ap_full_legalizer::Naive:
return std::make_unique<NaiveFullLegalizer>(ap_netlist,
atom_netlist,
prepacker,
vpr_setup,
arch,
device_grid,
logical_block_types);
case e_ap_full_legalizer::APPack:
return std::make_unique<APPack>(ap_netlist,
atom_netlist,
prepacker,
vpr_setup,
arch,
device_grid,
logical_block_types);
default:
VPR_FATAL_ERROR(VPR_ERROR_AP,
"Unrecognized full legalizer type");
}
}

namespace {

/// @brief A unique ID for each root tile on the device.
Expand Down Expand Up @@ -239,24 +276,24 @@ static LegalizationClusterId create_new_cluster(PackMoleculeId seed_molecule_id,
return LegalizationClusterId();
}

void FullLegalizer::create_clusters(const PartialPlacement& p_placement) {
void NaiveFullLegalizer::create_clusters(const PartialPlacement& p_placement) {
// PACKING:
// Initialize the cluster legalizer (Packing)
// FIXME: The legalization strategy is currently set to full. Should handle
// this better to make it faster.
t_pack_high_fanout_thresholds high_fanout_thresholds(packer_opts_.high_fanout_threshold);
t_pack_high_fanout_thresholds high_fanout_thresholds(vpr_setup_.PackerOpts.high_fanout_threshold);
ClusterLegalizer cluster_legalizer(atom_netlist_,
prepacker_,
logical_block_types_,
lb_type_rr_graphs_,
user_models_,
library_models_,
packer_opts_.target_external_pin_util,
vpr_setup_.PackerRRGraph,
arch_.models,
arch_.model_library,
vpr_setup_.PackerOpts.target_external_pin_util,
high_fanout_thresholds,
ClusterLegalizationStrategy::FULL,
packer_opts_.enable_pin_feasibility_filter,
packer_opts_.feasible_block_array_size,
packer_opts_.pack_verbosity);
vpr_setup_.PackerOpts.enable_pin_feasibility_filter,
vpr_setup_.PackerOpts.feasible_block_array_size,
vpr_setup_.PackerOpts.pack_verbosity);
// Create clusters for each tile.
// Start by giving each root tile a unique ID.
size_t grid_width = device_grid_.width();
Expand Down Expand Up @@ -330,24 +367,24 @@ void FullLegalizer::create_clusters(const PartialPlacement& p_placement) {

// Check and output the clustering.
std::unordered_set<AtomNetId> is_clock = alloc_and_load_is_clock();
check_and_output_clustering(cluster_legalizer, packer_opts_, is_clock, arch_);
check_and_output_clustering(cluster_legalizer, vpr_setup_.PackerOpts, is_clock, &arch_);
// Reset the cluster legalizer. This is required to load the packing.
cluster_legalizer.reset();
// Regenerate the clustered netlist from the file generated previously.
// FIXME: This writing and loading from a file is wasteful. Should generate
// the clusters directly from the cluster legalizer.
vpr_load_packing(vpr_setup_, *arch_);
vpr_load_packing(vpr_setup_, arch_);
load_cluster_constraints();
const ClusteredNetlist& clb_nlist = g_vpr_ctx.clustering().clb_nlist;

// Verify the packing and print some info
check_netlist(packer_opts_.pack_verbosity);
check_netlist(vpr_setup_.PackerOpts.pack_verbosity);
writeClusteredNetlistStats(vpr_setup_.FileNameOpts.write_block_usage);
print_pb_type_count(clb_nlist);
}

void FullLegalizer::place_clusters(const ClusteredNetlist& clb_nlist,
const PartialPlacement& p_placement) {
void NaiveFullLegalizer::place_clusters(const ClusteredNetlist& clb_nlist,
const PartialPlacement& p_placement) {
// PLACING:
// Create a lookup from the AtomBlockId to the APBlockId
vtr::vector<AtomBlockId, APBlockId> atom_to_ap_block(atom_netlist_.blocks().size());
Expand Down Expand Up @@ -409,7 +446,7 @@ void FullLegalizer::place_clusters(const ClusteredNetlist& clb_nlist,
// - This may be needed to perform SA. Not needed right now.
}

void FullLegalizer::legalize(const PartialPlacement& p_placement) {
void NaiveFullLegalizer::legalize(const PartialPlacement& p_placement) {
// Create a scoped timer for the full legalizer
vtr::ScopedStartFinishTimer full_legalizer_timer("AP Full Legalizer");

Expand Down Expand Up @@ -449,3 +486,65 @@ void FullLegalizer::legalize(const PartialPlacement& p_placement) {
post_place_sync();
}

void APPack::legalize(const PartialPlacement& p_placement) {
// Create a scoped timer for the full legalizer
vtr::ScopedStartFinishTimer full_legalizer_timer("AP Full Legalizer");

// Convert the Partial Placement (APNetlist) to a flat placement (AtomNetlist).
FlatPlacementInfo flat_placement_info(atom_netlist_);
for (APBlockId ap_blk_id : ap_netlist_.blocks()) {
PackMoleculeId mol_id = ap_netlist_.block_molecule(ap_blk_id);
const t_pack_molecule& mol = prepacker_.get_molecule(mol_id);
for (AtomBlockId atom_blk_id : mol.atom_block_ids) {
if (!atom_blk_id.is_valid())
continue;
flat_placement_info.blk_x_pos[atom_blk_id] = p_placement.block_x_locs[ap_blk_id];
flat_placement_info.blk_y_pos[atom_blk_id] = p_placement.block_y_locs[ap_blk_id];
flat_placement_info.blk_layer[atom_blk_id] = p_placement.block_layer_nums[ap_blk_id];
flat_placement_info.blk_sub_tile[atom_blk_id] = p_placement.block_sub_tiles[ap_blk_id];
}
}

// Run the Packer stage with the flat placement as a hint.
try_pack(&vpr_setup_.PackerOpts,
&vpr_setup_.AnalysisOpts,
arch_,
vpr_setup_.RoutingArch,
vpr_setup_.user_models,
vpr_setup_.library_models,
vpr_setup_.PackerRRGraph,
flat_placement_info);

// The Packer stores the clusters into a .net file. Load the packing file.
// FIXME: This should be removed. Reading from a file is strange.
vpr_load_packing(vpr_setup_, arch_);
load_cluster_constraints();
const ClusteredNetlist& clb_nlist = g_vpr_ctx.clustering().clb_nlist;

// Verify the packing and print some info
check_netlist(vpr_setup_.PackerOpts.pack_verbosity);
writeClusteredNetlistStats(vpr_setup_.FileNameOpts.write_block_usage);
print_pb_type_count(clb_nlist);

// Pass the clustering into the Placer with the flat placement as a hint.
// TODO: This should only be the initial placer. Running the full SA would
// be more of a Detailed Placer.
const auto& placement_net_list = (const Netlist<>&)clb_nlist;
try_place(placement_net_list,
vpr_setup_.PlacerOpts,
vpr_setup_.RouterOpts,
vpr_setup_.AnalysisOpts,
vpr_setup_.NocOpts,
arch_.Chans,
&vpr_setup_.RoutingArch,
vpr_setup_.Segments,
arch_.directs,
flat_placement_info,
false /* is_flat */);

// TODO: This was taken from vpr_api. Not sure why it is needed. Should be
// made part of the placement and verify placement should check for
// it.
post_place_sync();
}

Loading

0 comments on commit 25e2450

Please sign in to comment.