From d3967a6de8722443334a2c58c47409f833a66864 Mon Sep 17 00:00:00 2001 From: AlexandreSinger Date: Sun, 19 Jan 2025 21:39:26 -0500 Subject: [PATCH] [APPack] Added Layer to Flat Placement As per Vaughn's suggestions, added layer to the flat placement file specification to make it easier to upgrade to 3D FPGAs in the future. Fixed some small documentation issues. --- doc/src/vpr/command_line_usage.rst | 39 +++++++++++++++++++------- vpr/src/base/FlatPlacementInfo.h | 17 +++++++++-- vpr/src/base/load_flat_place.cpp | 27 ++++++++++-------- vpr/src/pack/pack.h | 22 +++++++++++++++ vpr/src/pack/verify_flat_placement.cpp | 13 +++++++-- 5 files changed, 91 insertions(+), 27 deletions(-) diff --git a/doc/src/vpr/command_line_usage.rst b/doc/src/vpr/command_line_usage.rst index f6cdf73eff..920f91e712 100644 --- a/doc/src/vpr/command_line_usage.rst +++ b/doc/src/vpr/command_line_usage.rst @@ -411,23 +411,42 @@ Use the options below to override this default naming behaviour. .. option:: --read_flat_place Reads a file containing the locations of each atom on the FPGA. - This is used by the packer to better cluster atoms together. The flat placement file (which often ends in ``.fplace``) is a text file - where each line describes the location of an atom. It has the following - expected syntax: + where each line describes the location of an atom. Each line in the flat + placement file should have the following syntax: .. code-block:: none - - n523 6 8 0 3 - n522 6 8 0 5 - n520 6 8 0 2 - n518 6 8 0 16 + + + For example: + + .. code-block:: none - The ``sub_tile`` and ``site_idx`` are optional parameters which may be used - as a hint to reconstruct clusters. + n523 6 8 0 0 3 + n522 6 8 0 0 5 + n520 6 8 0 0 2 + n518 6 8 0 0 16 + + The position of the atom on the FPGA is given by 3 floating point values + (``x``, ``y``, ``layer``). We allow for the positions of atom to be not + quite legal (ok to be off-grid) since this flat placement will be fed into + the packer and placer, which will snap the positions to grid locations. By + allowing for off-grid positions, the packer can better trade-off where to + move atom blocks if they cannot be placed at the given position. + For 2D FPGA architectures, the ``layer`` should be 0. + + The ``sub_tile`` is a clustered placement construct: which cluster-level + location at a given (x, y, layer) should these atoms go at (relevant when + multiple clusters can be stacked there). A sub-tile of -1 may be used when + the sub-tile of an atom is unkown (allowing the packing algorithm to choose + any sub-tile at the given (x, y, layer) location). + + The ``site_idx`` is an optional index into a linearized list of primitive + locations within a cluster-level block which may be used as a hint to + reconstruct clusters. .. warning:: diff --git a/vpr/src/base/FlatPlacementInfo.h b/vpr/src/base/FlatPlacementInfo.h index a3d199bbc9..4f3ca3e5e8 100644 --- a/vpr/src/base/FlatPlacementInfo.h +++ b/vpr/src/base/FlatPlacementInfo.h @@ -26,15 +26,27 @@ class FlatPlacementInfo { /// @brief Identifier for an undefined site idx. static constexpr int UNDEFINED_SITE_IDX = -1; + // The following three floating point numbers describe the flat position of + // an atom block. These are floats instead of integers to allow for flat + // placements which are not quite legal (ok to be off-grid). This allows + // the flat placement to encode information about where atom blocks would + // want to go if they cannot be placed at the grid position they are at. + // (for example, a block placed at (0.9, 0.9) wants to be at tile (0, 0), + // but if thats not possible it would prefer (1, 1) over anything else. + /// @brief The x-positions of each atom block. Is UNDEFINED_POS if undefined. vtr::vector blk_x_pos; /// @brief The y-positions of each atom block. Is UNDEFINED_POS if undefined. vtr::vector blk_y_pos; + /// @brief The layer of each atom block. Is UNDEFINED_POS if undefined. + vtr::vector blk_layer; + /// @brief The sub tile location of each atom block. Is UNDEFINED_SUB_TILE /// if undefined. vtr::vector blk_sub_tile; - /// @brief The flat site idx of each atom block. Is UNDEFINED_SITE_IDX if - /// undefined. + /// @brief The flat site idx of each atom block. This is an optional index + /// into a linearized list of primitive locations within a cluster- + /// level block. Is UNDEFINED_SITE_IDX if undefined. vtr::vector blk_site_idx; /// @brief A flag to signify if this object has been constructed with data @@ -64,6 +76,7 @@ class FlatPlacementInfo { FlatPlacementInfo(const AtomNetlist& atom_netlist) : blk_x_pos(atom_netlist.blocks().size(), UNDEFINED_POS), blk_y_pos(atom_netlist.blocks().size(), UNDEFINED_POS), + blk_layer(atom_netlist.blocks().size(), UNDEFINED_POS), blk_sub_tile(atom_netlist.blocks().size(), UNDEFINED_SUB_TILE), blk_site_idx(atom_netlist.blocks().size(), UNDEFINED_SITE_IDX), valid(true) {} diff --git a/vpr/src/base/load_flat_place.cpp b/vpr/src/base/load_flat_place.cpp index 2bd7c7fbf4..04a141e3b4 100644 --- a/vpr/src/base/load_flat_place.cpp +++ b/vpr/src/base/load_flat_place.cpp @@ -50,9 +50,10 @@ static void print_flat_cluster(FILE* fp, t_pb_graph_node* atom_pbgn = atom_ctx.lookup.atom_pb(atom)->pb_graph_node; // Print the flat placement information for this atom. - fprintf(fp, "%s %d %d %d %d #%zu %s\n", + fprintf(fp, "%s %d %d %d %d %d #%zu %s\n", atom_ctx.nlist.block_name(atom).c_str(), - blk_loc.x, blk_loc.y, blk_loc.sub_tile, + blk_loc.x, blk_loc.y, blk_loc.layer, + blk_loc.sub_tile, atom_pbgn->flat_site_index, static_cast(blk_id), atom_pbgn->pb_type->name); @@ -111,9 +112,11 @@ FlatPlacementInfo read_flat_placement(const std::string& read_flat_place_file_pa // - Atom name // - Atom x-pos // - Atom y-pos - if (tokens.size() < 3) { + // - Atom layer + // - Atom sub-tile + if (tokens.size() < 5) { VTR_LOG_WARN("Flat placement file, line %d has too few arguments. " - "Requires at least: \n", + "Requires at least: \n", line_num); continue; } @@ -137,19 +140,19 @@ FlatPlacementInfo read_flat_placement(const std::string& read_flat_place_file_pa continue; } - // Get the x and y position of the atom. These functions have error - // checking built in. We parse x and y as floats to allow for reading - // in more global atom positions. + // Get the (x, y, layer) position of the atom. These functions have + // error checking built in. We parse these as floats to allow for + // reading in more global atom positions. flat_placement_info.blk_x_pos[atom_blk_id] = vtr::atof(tokens[1]); flat_placement_info.blk_y_pos[atom_blk_id] = vtr::atof(tokens[2]); + flat_placement_info.blk_layer[atom_blk_id] = vtr::atof(tokens[3]); - // If a sub-tile is given, parse the sub-tile as an integer. - if (tokens.size() >= 4 && tokens[3][0] != '#') - flat_placement_info.blk_sub_tile[atom_blk_id] = vtr::atoi(tokens[3]); + // Parse the sub-tile as an integer. + flat_placement_info.blk_sub_tile[atom_blk_id] = vtr::atoi(tokens[4]); // If a site index is given, parse the site index as an integer. - if (tokens.size() >= 5 && tokens[4][0] != '#') - flat_placement_info.blk_site_idx[atom_blk_id] = vtr::atoi(tokens[4]); + if (tokens.size() >= 6 && tokens[5][0] != '#') + flat_placement_info.blk_site_idx[atom_blk_id] = vtr::atoi(tokens[5]); // Ignore any further tokens. diff --git a/vpr/src/pack/pack.h b/vpr/src/pack/pack.h index 36f5d76c14..00fba353da 100644 --- a/vpr/src/pack/pack.h +++ b/vpr/src/pack/pack.h @@ -12,6 +12,28 @@ struct t_lb_type_rr_node; struct t_model; struct t_packer_opts; +/** + * @brief Try to pack the atom netlist into legal clusters on the given + * architecture. Will return true if successful, false otherwise. + * + * @param packer_opts + * Options passed by the user to configure the packing algorithm. + * @param analysis_opts + * Options passed by the user to configure how analysis is + * performed in the packer. + * @param arch + * A pointer to the architecture to create clusters for. + * @param user_models + * A list of architecture models provided by the architecture file. + * @param library_models + * A list of architecture models provided by the library. + * @param interc_delay + * @param lb_type_rr_graphs + * @param flat_placement_info + * Flat (primitive-level) placement information that may be + * provided by the user as a hint for packing. Will be invalid if + * there is no flat placement information provided. + */ bool try_pack(t_packer_opts* packer_opts, const t_analysis_opts* analysis_opts, const t_arch* arch, diff --git a/vpr/src/pack/verify_flat_placement.cpp b/vpr/src/pack/verify_flat_placement.cpp index e13637e85b..00e4b25987 100644 --- a/vpr/src/pack/verify_flat_placement.cpp +++ b/vpr/src/pack/verify_flat_placement.cpp @@ -16,6 +16,7 @@ unsigned verify_flat_placement_for_packing(const FlatPlacementInfo& flat_placeme // for each piece of information. if (flat_placement_info.blk_x_pos.size() != atom_netlist.blocks().size() || flat_placement_info.blk_y_pos.size() != atom_netlist.blocks().size() || + flat_placement_info.blk_layer.size() != atom_netlist.blocks().size() || flat_placement_info.blk_sub_tile.size() != atom_netlist.blocks().size() || flat_placement_info.blk_site_idx.size() != atom_netlist.blocks().size()) { VTR_LOG_ERROR( @@ -26,14 +27,14 @@ unsigned verify_flat_placement_for_packing(const FlatPlacementInfo& flat_placeme return num_errors; } - // 1. Verify that every atom has an x and y position on the device. This is - // the only information we require for the flat placement during packing. + // 1. Verify that every atom has an (x, y, layer) position on the device. // // TODO: In the future, we may be able to allow some blocks to have // undefined positions. for (AtomBlockId blk_id : atom_netlist.blocks()) { if (flat_placement_info.blk_x_pos[blk_id] == FlatPlacementInfo::UNDEFINED_POS || - flat_placement_info.blk_y_pos[blk_id] == FlatPlacementInfo::UNDEFINED_POS) { + flat_placement_info.blk_y_pos[blk_id] == FlatPlacementInfo::UNDEFINED_POS || + flat_placement_info.blk_layer[blk_id] == FlatPlacementInfo::UNDEFINED_POS) { VTR_LOG_ERROR( "Atom block %s has an undefined position in the flat placement.\n", atom_netlist.block_name(blk_id).c_str()); @@ -49,10 +50,12 @@ unsigned verify_flat_placement_for_packing(const FlatPlacementInfo& flat_placeme for (AtomBlockId blk_id : atom_netlist.blocks()) { float blk_x_pos = flat_placement_info.blk_x_pos[blk_id]; float blk_y_pos = flat_placement_info.blk_y_pos[blk_id]; + float blk_layer = flat_placement_info.blk_layer[blk_id]; int blk_sub_tile = flat_placement_info.blk_sub_tile[blk_id]; int blk_site_idx = flat_placement_info.blk_site_idx[blk_id]; if ((blk_x_pos < 0.f && blk_x_pos != FlatPlacementInfo::UNDEFINED_POS) || (blk_y_pos < 0.f && blk_y_pos != FlatPlacementInfo::UNDEFINED_POS) || + (blk_layer < 0.f && blk_layer != FlatPlacementInfo::UNDEFINED_POS) || (blk_sub_tile < 0 && blk_sub_tile != FlatPlacementInfo::UNDEFINED_SUB_TILE) || (blk_site_idx < 0 && blk_site_idx != FlatPlacementInfo::UNDEFINED_SITE_IDX)) { VTR_LOG_ERROR( @@ -71,12 +74,14 @@ unsigned verify_flat_placement_for_packing(const FlatPlacementInfo& flat_placeme AtomBlockId root_blk_id = mol->atom_block_ids[mol->root]; float root_pos_x = flat_placement_info.blk_x_pos[root_blk_id]; float root_pos_y = flat_placement_info.blk_y_pos[root_blk_id]; + float root_layer = flat_placement_info.blk_layer[root_blk_id]; int root_sub_tile = flat_placement_info.blk_sub_tile[root_blk_id]; for (AtomBlockId mol_blk_id : mol->atom_block_ids) { if (!mol_blk_id.is_valid()) continue; if (flat_placement_info.blk_x_pos[mol_blk_id] != root_pos_x || flat_placement_info.blk_y_pos[mol_blk_id] != root_pos_y || + flat_placement_info.blk_layer[mol_blk_id] != root_layer || flat_placement_info.blk_sub_tile[mol_blk_id] != root_sub_tile) { VTR_LOG_ERROR( "Molecule with root atom block %s contains atom block %s " @@ -89,6 +94,8 @@ unsigned verify_flat_placement_for_packing(const FlatPlacementInfo& flat_placeme } } + // TODO: May want to verify that the layer is all 0 in the case of 2D FPGAs. + return num_errors; }