diff --git a/vpr/src/analytical_place/analytical_placement_flow.cpp b/vpr/src/analytical_place/analytical_placement_flow.cpp index 425b191dbb3..089995e1cad 100644 --- a/vpr/src/analytical_place/analytical_placement_flow.cpp +++ b/vpr/src/analytical_place/analytical_placement_flow.cpp @@ -59,6 +59,83 @@ static void print_ap_netlist_stats(const APNetlist& netlist) { VTR_LOG("\n"); } +/** + * @brief Passes the flat placement information to a provided partial placement. + * + * @param flat_placement_info The flat placement information to be read. + * @param ap_netlist The APNetlist that used to iterate over its blocks. + * @param prepacker The Prepacker to get molecule of blocks in the ap_netlist. + * @param p_placement The partial placement to be updated which is assumend + * to be generated on ap_netlist or have the same blocks. + */ +static void convert_flat_to_partial_placement(const FlatPlacementInfo& flat_placement_info, const APNetlist& ap_netlist, const Prepacker& prepacker, PartialPlacement& p_placement){ + for (APBlockId ap_blk_id : ap_netlist.blocks()) { + // Get the molecule that AP block represents + PackMoleculeId mol_id = ap_netlist.block_molecule(ap_blk_id); + const t_pack_molecule& mol = prepacker.get_molecule(mol_id); + // Get location of a valid atom in the molecule and verify that + // all atoms of the molecule share same placement information. + float atom_loc_x, atom_loc_y, atom_loc_layer; + int atom_loc_sub_tile; + bool found_valid_atom = false; + for (AtomBlockId atom_blk_id: mol.atom_block_ids) { + if (!atom_blk_id.is_valid()) + continue; + float current_loc_x = flat_placement_info.blk_x_pos[atom_blk_id]; + float current_loc_y = flat_placement_info.blk_y_pos[atom_blk_id]; + float current_loc_layer = flat_placement_info.blk_layer[atom_blk_id]; + int current_loc_sub_tile = flat_placement_info.blk_sub_tile[atom_blk_id]; + if (found_valid_atom) { + if (current_loc_x != atom_loc_x || current_loc_y != atom_loc_y || current_loc_layer != atom_loc_layer || current_loc_sub_tile != atom_loc_sub_tile) + VPR_FATAL_ERROR(VPR_ERROR_AP, "Molecule of ID %zu contains atom %s (ID: %zu) with a location (%g, %g, layer: %g, subtile: %d) " + "that conflicts the location of other atoms in this molecule of (%g, %g, layer: %g, subtile: %d).", + mol_id, g_vpr_ctx.atom().netlist().block_name(atom_blk_id).c_str(), atom_blk_id, + current_loc_x, current_loc_y, current_loc_layer, current_loc_sub_tile, + atom_loc_x, atom_loc_y, atom_loc_layer, atom_loc_sub_tile); + } else { + atom_loc_x = current_loc_x; + atom_loc_y = current_loc_y; + atom_loc_layer = current_loc_layer; + atom_loc_sub_tile = current_loc_sub_tile; + found_valid_atom = true; + } + } + // Ensure that there is a valid atom in the molecule to pass its location. + VTR_ASSERT_MSG(found_valid_atom, "Each molecule must contain at least one valid atom"); + // Pass the placement information + p_placement.block_x_locs[ap_blk_id] = atom_loc_x; + p_placement.block_y_locs[ap_blk_id] = atom_loc_y; + p_placement.block_layer_nums[ap_blk_id] = atom_loc_layer; + p_placement.block_sub_tiles[ap_blk_id] = atom_loc_sub_tile; + } +} + +/** + * @brief If a flat placement is provided, skips the Global Placer and + * converts it to a partial placement. Otherwise, runs the Global Placer. + */ +static PartialPlacement run_global_placer(const AtomNetlist& atom_nlist, const APNetlist& ap_netlist, const Prepacker& prepacker, const DeviceContext& device_ctx) { + if (g_vpr_ctx.atom().flat_placement_info().valid) { + VTR_LOG("Flat Placement is provided in the AP flow, skipping the Global Placement.\n"); + PartialPlacement p_placement(ap_netlist); + convert_flat_to_partial_placement(g_vpr_ctx.atom().flat_placement_info(), + ap_netlist, + prepacker, + p_placement); + return p_placement; + } else { + // Run the Global Placer + std::unique_ptr global_placer = make_global_placer(e_global_placer::SimPL, + ap_netlist, + prepacker, + atom_nlist, + device_ctx.grid, + device_ctx.logical_block_types, + device_ctx.physical_tile_types); + return global_placer->place(); + } +} + void run_analytical_placement_flow(t_vpr_setup& vpr_setup) { // Start an overall timer for the Analytical Placement flow. vtr::ScopedStartFinishTimer timer("Analytical Placement"); @@ -78,15 +155,11 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) { constraints); print_ap_netlist_stats(ap_netlist); - // Run the Global Placer - std::unique_ptr global_placer = make_global_placer(e_global_placer::SimPL, - ap_netlist, - prepacker, - atom_nlist, - device_ctx.grid, - device_ctx.logical_block_types, - device_ctx.physical_tile_types); - PartialPlacement p_placement = global_placer->place(); + // Run the Global Placer. + PartialPlacement p_placement = run_global_placer(atom_nlist, + ap_netlist, + prepacker, + device_ctx); // Verify that the partial placement is valid before running the full // legalizer. diff --git a/vpr/src/analytical_place/ap_flow_enums.h b/vpr/src/analytical_place/ap_flow_enums.h index 4e996cba8e1..6a1148499c1 100644 --- a/vpr/src/analytical_place/ap_flow_enums.h +++ b/vpr/src/analytical_place/ap_flow_enums.h @@ -15,7 +15,8 @@ */ 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. + APPack, ///< The APPack Full Legalizer, which uses the flat placement to improve the Packer and Placer. + Basic_Min_Disturbance ///< The Basic Min. Disturbance Full Legalizer, which tries to reconstruct a clustered placement that is as close to the incoming flat placement as it can. }; /** diff --git a/vpr/src/analytical_place/full_legalizer.cpp b/vpr/src/analytical_place/full_legalizer.cpp index ae6a2806769..51978a0e029 100644 --- a/vpr/src/analytical_place/full_legalizer.cpp +++ b/vpr/src/analytical_place/full_legalizer.cpp @@ -77,6 +77,11 @@ std::unique_ptr make_full_legalizer(e_ap_full_legalizer full_lega vpr_setup, arch, device_grid); + case e_ap_full_legalizer::Basic_Min_Disturbance: + VTR_LOG("Basic Minimum Disturbance Full Legalizer selected!\n"); + VPR_FATAL_ERROR(VPR_ERROR_AP, + "Basic Min. Disturbance Full Legalizer has not been implemented yet."); + default: VPR_FATAL_ERROR(VPR_ERROR_AP, "Unrecognized full legalizer type"); diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index 5f743f42abd..730490fe2be 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -603,6 +603,9 @@ static void ShowAnalyticalPlacerOpts(const t_ap_opts& APOpts) { case e_ap_full_legalizer::APPack: VTR_LOG("appack\n"); break; + case e_ap_full_legalizer::Basic_Min_Disturbance: + VTR_LOG("basic-min-disturbance\n"); + break; default: VPR_FATAL_ERROR(VPR_ERROR_UNKNOWN, "Unknown full_legalizer_type\n"); } diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 6a42a6b6646..bd9d400a80e 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -141,6 +141,8 @@ struct ParseAPFullLegalizer { conv_value.set_value(e_ap_full_legalizer::Naive); else if (str == "appack") conv_value.set_value(e_ap_full_legalizer::APPack); + else if (str == "basic-min-disturbance") + conv_value.set_value(e_ap_full_legalizer::Basic_Min_Disturbance); else { std::stringstream msg; msg << "Invalid conversion from '" << str << "' to e_ap_full_legalizer (expected one of: " << argparse::join(default_choices(), ", ") << ")"; @@ -158,6 +160,8 @@ struct ParseAPFullLegalizer { case e_ap_full_legalizer::APPack: conv_value.set_value("appack"); break; + case e_ap_full_legalizer::Basic_Min_Disturbance: + conv_value.set_value("basic-min-disturbance"); default: VTR_ASSERT(false); } @@ -165,7 +169,7 @@ struct ParseAPFullLegalizer { } std::vector default_choices() { - return {"naive", "appack"}; + return {"naive", "appack", "basic-min-disturbance"}; } }; @@ -1822,7 +1826,8 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .help( "Controls which Full Legalizer to use in the AP Flow.\n" " * naive: Use a Naive Full Legalizer which will try to create clusters exactly where their atoms are placed.\n" - " * appack: Use APPack, which takes the Packer in VPR and uses the flat atom placement to create better clusters.") + " * appack: Use APPack, which takes the Packer in VPR and uses the flat atom placement to create better clusters.\n" + " * basic-min-disturbance: Use the Basic Min. Disturbance Full Legalizer which tries to reconstruct a clustered placement that is as close to the incoming flat placement as possible.\n") .default_value("appack") .show_in(argparse::ShowIn::HELP_ONLY); diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 2265f26b4ef..b39a8072f3a 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -404,8 +404,25 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) { { // Analytical Place if (vpr_setup.APOpts.doAP == STAGE_DO) { + // Passing flat placement input if provided and not loaded yet. + if (!vpr_setup.FileNameOpts.read_flat_place_file.empty() && + !g_vpr_ctx.atom().flat_placement_info().valid) { + g_vpr_ctx.mutable_atom().mutable_flat_placement_info() = read_flat_placement( + vpr_setup.FileNameOpts.read_flat_place_file, + g_vpr_ctx.atom().netlist()); + } + // TODO: Make this return a bool if the placement was successful or not. run_analytical_placement_flow(vpr_setup); + + // Write out a flat placement file at the end of Analytical Placement + // flow if the option is specified. + if (!vpr_setup.FileNameOpts.write_flat_place_file.empty()) { + write_flat_placement(vpr_setup.FileNameOpts.write_flat_place_file.c_str(), + g_vpr_ctx.clustering().clb_nlist, + g_vpr_ctx.placement().block_locs(), + g_vpr_ctx.clustering().atoms_lookup); + } } // Print the placement generated by AP to a .place file. auto& filename_opts = vpr_setup.FileNameOpts;