Skip to content

Commit

Permalink
Merge pull request verilog-to-routing#2615 from verilog-to-routing/le…
Browse files Browse the repository at this point in the history
…galizer_frontend

legalizer frontend
  • Loading branch information
vaughnbetz authored Jun 19, 2024
2 parents 871b28a + cc0a460 commit 95b8fee
Show file tree
Hide file tree
Showing 15 changed files with 225 additions and 18 deletions.
12 changes: 12 additions & 0 deletions vpr/src/base/CheckSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ void CheckSetup(const t_packer_opts& PackerOpts,
"Packing cannot be timing driven without timing analysis enabled\n");
}

if (PackerOpts.load_flat_placement) {
if (PackerOpts.device_layout == "auto") {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Legalization requires a fixed device layout.\n");
}
if (!PlacerOpts.constraints_file.empty()) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
"Cannot specify a fixed clusters file when running legalization.\n");
}
}


if ((GLOBAL == RouterOpts.route_type)
&& (PlacerOpts.place_algorithm.is_timing_driven())) {
/* Works, but very weird. Can't optimize timing well, since you're
Expand Down
5 changes: 3 additions & 2 deletions vpr/src/base/SetupGrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
#include "physical_types.h"

///@brief Find the device satisfying the specified minimum resources
/// minimum_instance_counts and target_device_utilization are not required when specifying a fixed layout
DeviceGrid create_device_grid(const std::string& layout_name,
const std::vector<t_grid_def>& grid_layouts,
const std::map<t_logical_block_type_ptr, size_t>& minimum_instance_counts,
float target_device_utilization);
const std::map<t_logical_block_type_ptr, size_t>& minimum_instance_counts = {},
float target_device_utilization = 0.0);

///@brief Find the device close in size to the specified dimensions
DeviceGrid create_device_grid(const std::string& layout_name,
Expand Down
9 changes: 9 additions & 0 deletions vpr/src/base/SetupVPR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void SetupVPR(const t_options* Options,
FileNameOpts->ArchFile = Options->ArchFile;
FileNameOpts->CircuitFile = Options->CircuitFile;
FileNameOpts->NetFile = Options->NetFile;
FileNameOpts->FlatPlaceFile = Options->FlatPlaceFile;
FileNameOpts->PlaceFile = Options->PlaceFile;
FileNameOpts->RouteFile = Options->RouteFile;
FileNameOpts->ActFile = Options->ActFile;
Expand All @@ -136,6 +137,8 @@ void SetupVPR(const t_options* Options,
FileNameOpts->out_file_prefix = Options->out_file_prefix;
FileNameOpts->read_vpr_constraints_file = Options->read_vpr_constraints_file;
FileNameOpts->write_vpr_constraints_file = Options->write_vpr_constraints_file;
FileNameOpts->write_constraints_file = Options->write_constraints_file;
FileNameOpts->write_flat_place_file = Options->write_flat_place_file;
FileNameOpts->write_block_usage = Options->write_block_usage;

FileNameOpts->verify_file_digests = Options->verify_file_digests;
Expand Down Expand Up @@ -239,6 +242,7 @@ void SetupVPR(const t_options* Options,
//Setup the default flow, if no specific stages specified
//do all
if (!Options->do_packing
&& !Options->do_legalize
&& !Options->do_placement
&& !Options->do_routing
&& !Options->do_analysis) {
Expand Down Expand Up @@ -275,6 +279,11 @@ void SetupVPR(const t_options* Options,
if (Options->do_packing) {
PackerOpts->doPacking = STAGE_DO;
}

if (Options->do_legalize) {
PackerOpts->doPacking = STAGE_LOAD;
PackerOpts->load_flat_placement = true;
}
}

ShowSetup(*vpr_setup);
Expand Down
3 changes: 3 additions & 0 deletions vpr/src/base/echo_files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ void alloc_and_load_echo_file_info() {
//Packing
setEchoFileName(E_ECHO_CLUSTERS, "clusters.echo");

//Legalizer
setEchoFileName(E_ECHO_FLAT_PLACE, "post_legalizer_flat_placement.echo");

//Intra-block routing
setEchoFileName(E_ECHO_INTRA_LB_FAILED_ROUTE, "intra_lb_failed_route.echo");

Expand Down
3 changes: 3 additions & 0 deletions vpr/src/base/echo_files.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ enum e_echo_files {
//Packing
E_ECHO_CLUSTERS,

//Legalizer
E_ECHO_FLAT_PLACE,

// Intra-block routing
E_ECHO_INTRA_LB_FAILED_ROUTE,

Expand Down
55 changes: 55 additions & 0 deletions vpr/src/base/load_flat_place.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "globals.h"
#include "load_flat_place.h"
#include "clustered_netlist_utils.h"


/* @brief Prints flat placement file entries for the atoms in one placed cluster. */
static void print_flat_cluster(FILE* fp, ClusterBlockId iblk,
std::vector<AtomBlockId>& atoms);

static void print_flat_cluster(FILE* fp, ClusterBlockId iblk,
std::vector<AtomBlockId>& atoms) {

auto& atom_ctx = g_vpr_ctx.atom();
t_pl_loc loc = g_vpr_ctx.placement().block_locs[iblk].loc;
size_t bnum = size_t(iblk);

for (auto atom : atoms) {
t_pb_graph_node* atom_pbgn = atom_ctx.lookup.atom_pb(atom)->pb_graph_node;
fprintf(fp, "%s %d %d %d %d #%zu %s\n", atom_ctx.nlist.block_name(atom).c_str(),
loc.x, loc.y, loc.sub_tile,
atom_pbgn->flat_site_index,
bnum,
atom_pbgn->pb_type->name);
}
}

/* prints a flat placement file */
void print_flat_placement(const char* flat_place_file) {

FILE* fp;

ClusterAtomsLookup atoms_lookup;
auto& cluster_ctx = g_vpr_ctx.clustering();

if (!g_vpr_ctx.placement().block_locs.empty()) {
fp = fopen(flat_place_file, "w");
for (auto iblk : cluster_ctx.clb_nlist.blocks()) {
auto atoms = atoms_lookup.atoms_in_cluster(iblk);
print_flat_cluster(fp, iblk, atoms);
}
fclose(fp);
}

}

/* ingests and legalizes a flat placement file */
bool load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch) {
VTR_LOG("load_flat_placement(); when implemented, this function:");
VTR_LOG("\n\tLoads flat placement file: %s, ", vpr_setup.FileNameOpts.FlatPlaceFile.c_str());
VTR_LOG("\n\tArch id: %s, ", arch.architecture_id);
VTR_LOG("\n\tPrints clustered netlist file: %s, ", vpr_setup.FileNameOpts.NetFile.c_str());
VTR_LOG("\n\tPrints fix clusters file: %s\n", vpr_setup.FileNameOpts.write_constraints_file.c_str());

return false;
}
16 changes: 16 additions & 0 deletions vpr/src/base/load_flat_place.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef LOAD_FLAT_PLACE_H
#define LOAD_FLAT_PLACE_H

#include "vpr_types.h"

/**
* @brief A function that prints a flat placement file
*/
void print_flat_placement(const char* flat_place_file);

/**
* @brief A function that loads and legalizes a flat placement file
*/
bool load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch);

#endif
20 changes: 20 additions & 0 deletions vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,11 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.action(argparse::Action::STORE_TRUE)
.default_value("off");

stage_grp.add_argument<bool, ParseOnOff>(args.do_legalize, "--legalize")
.help("Legalize a flat placement, i.e. reconstruct and place clusters based on a flat placement file, which lists cluster and intra-cluster placement coordinates for each primitive.")
.action(argparse::Action::STORE_TRUE)
.default_value("off");

stage_grp.add_argument<bool, ParseOnOff>(args.do_placement, "--place")
.help("Run placement")
.action(argparse::Action::STORE_TRUE)
Expand Down Expand Up @@ -1590,6 +1595,10 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.help("Path to packed netlist file")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.FlatPlaceFile, "--flat_place_file")
.help("Path to input flat placement file")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.PlaceFile, "--place_file")
.help("Path to placement file")
.show_in(argparse::ShowIn::HELP_ONLY);
Expand Down Expand Up @@ -1627,6 +1636,17 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.help("Writes out new floorplanning constraints based on current placement to the specified XML file.")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.write_constraints_file, "--write_fix_clusters")
.help(
"Output file containing fixed locations of legalized input clusters - does not include clusters without placement coordinates; this file is used during post-legalization placement in order to hold input placement coordinates fixed while VPR places legalizer-generated orphan clusters.")
.default_value("fix_clusters.out")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.write_flat_place_file, "--write_flat_place")
.help(
"VPR's (or reconstructed external) placement solution in flat placement file format; this file lists cluster and intra-cluster placement coordinates for each atom and can be used to reconstruct a clustering and placement solution.")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.read_router_lookahead, "--read_router_lookahead")
.help(
"Reads the lookahead data from the specified file instead of computing it.")
Expand Down
4 changes: 4 additions & 0 deletions vpr/src/base/read_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct t_options {
argparse::ArgValue<std::string> ArchFile;
argparse::ArgValue<std::string> CircuitName;
argparse::ArgValue<std::string> NetFile;
argparse::ArgValue<std::string> FlatPlaceFile;
argparse::ArgValue<std::string> PlaceFile;
argparse::ArgValue<std::string> RouteFile;
argparse::ArgValue<std::string> CircuitFile;
Expand All @@ -30,6 +31,8 @@ struct t_options {
argparse::ArgValue<std::string> write_initial_place_file;
argparse::ArgValue<std::string> read_vpr_constraints_file;
argparse::ArgValue<std::string> write_vpr_constraints_file;
argparse::ArgValue<std::string> write_constraints_file;
argparse::ArgValue<std::string> write_flat_place_file;

argparse::ArgValue<std::string> write_placement_delay_lookup;
argparse::ArgValue<std::string> read_placement_delay_lookup;
Expand All @@ -44,6 +47,7 @@ struct t_options {

/* Stage Options */
argparse::ArgValue<bool> do_packing;
argparse::ArgValue<bool> do_legalize;
argparse::ArgValue<bool> do_placement;
argparse::ArgValue<bool> do_routing;
argparse::ArgValue<bool> do_analysis;
Expand Down
21 changes: 14 additions & 7 deletions vpr/src/base/read_place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ void read_place_body(std::ifstream& placement_file,
*/
void print_place(const char* net_file,
const char* net_id,
const char* place_file) {
const char* place_file,
bool is_place_file) {
FILE* fp;

auto& device_ctx = g_vpr_ctx.device();
Expand All @@ -318,15 +319,21 @@ void print_place(const char* net_file,

fp = fopen(place_file, "w");

fprintf(fp, "Netlist_File: %s Netlist_ID: %s\n",
net_file,
net_id);
fprintf(fp, "Array size: %zu x %zu logic blocks\n\n", device_ctx.grid.width(), device_ctx.grid.height());
fprintf(fp, "#block name\tx\ty\tsubblk\tlayer\tblock number\n");
fprintf(fp, "#----------\t--\t--\t------\t-----\t------------\n");
if (is_place_file) {
fprintf(fp, "Netlist_File: %s Netlist_ID: %s\n",
net_file,
net_id);
fprintf(fp, "Array size: %zu x %zu logic blocks\n\n", device_ctx.grid.width(), device_ctx.grid.height());
fprintf(fp, "#block name\tx\ty\tsubblk\tlayer\tblock number\n");
fprintf(fp, "#----------\t--\t--\t------\t-----\t------------\n");
}

if (!place_ctx.block_locs.empty()) { //Only if placement exists
for (auto blk_id : cluster_ctx.clb_nlist.blocks()) {
// if block is not placed, skip (useful for printing legalizer output)
if (!is_place_file && (place_ctx.block_locs[blk_id].loc.x == INVALID_X)) {
continue;
}
fprintf(fp, "%s\t", cluster_ctx.clb_nlist.block_pb(blk_id)->name);
if (strlen(cluster_ctx.clb_nlist.block_pb(blk_id)->name) < 8)
fprintf(fp, "\t");
Expand Down
13 changes: 12 additions & 1 deletion vpr/src/base/read_place.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,19 @@ void read_place(
*/
void read_constraints(const char* constraints_file);

/**
* This function prints out a place file.
* @param is_place_file: defaults to true. If false, does not print file header; this is useful if
* the output will be used as a constraints file. If is_place_file is false,
* net_file and net_id parameters are not used and can be set to nullptr.
* Note: if false, only placed clusters are printed - clusters without
* placement coordinates (e.g. orphan clusters created during legalization
* will not be included; this file is used as a placement constraints
* file when running placement in order to place orphan clusters.
*/
void print_place(const char* net_file,
const char* net_id,
const char* place_file);
const char* place_file,
bool is_place_file = true);

#endif
67 changes: 63 additions & 4 deletions vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
#include "log.h"
#include "iostream"

#include "load_flat_place.h"

#ifdef VPR_USE_TBB
# define TBB_PREVIEW_GLOBAL_CONTROL 1 /* Needed for compatibility with old TBB versions */
# include <tbb/task_arena.h>
Expand Down Expand Up @@ -393,6 +395,7 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
return false; //Unimplementable
}
}

// For the time being, we decided to create the flat graph after placement is done. Thus, the is_flat parameter for this function
//, since it is called before routing, should be false.
vpr_create_device(vpr_setup, arch, false);
Expand Down Expand Up @@ -595,6 +598,9 @@ bool vpr_pack_flow(t_vpr_setup& vpr_setup, const t_arch& arch) {
if (packer_opts.doPacking == STAGE_DO) {
//Do the actual packing
status = vpr_pack(vpr_setup, arch);
if (!status) {
return status;
}

//TODO: to be consistent with placement/routing vpr_pack should really
// load the netlist data structures itself, instead of re-loading
Expand All @@ -604,10 +610,25 @@ bool vpr_pack_flow(t_vpr_setup& vpr_setup, const t_arch& arch) {
vpr_load_packing(vpr_setup, arch);
} else {
VTR_ASSERT(packer_opts.doPacking == STAGE_LOAD);
//Load a previous packing from the .net file
vpr_load_packing(vpr_setup, arch);
//Load cluster_constraints data structure here since loading pack file
load_cluster_constraints();

// generate a .net file by legalizing an input flat placement file
if (packer_opts.load_flat_placement) {

//Load and legalizer flat placement file
vpr_load_flat_placement(vpr_setup, arch);

//Load the result from the .net file
vpr_load_packing(vpr_setup, arch);

} else {

//Load a previous packing from the .net file
vpr_load_packing(vpr_setup, arch);

//Load cluster_constraints data structure here since loading pack file
load_cluster_constraints();
}

}

/* Sanity check the resulting netlist */
Expand Down Expand Up @@ -709,6 +730,37 @@ void vpr_load_packing(t_vpr_setup& vpr_setup, const t_arch& arch) {
}
}

bool vpr_load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch) {

// set up the device grid for the legalizer
auto& device_ctx = g_vpr_ctx.mutable_device();
device_ctx.arch = &arch;
device_ctx.grid = create_device_grid(vpr_setup.device_layout, arch.grid_layouts);
if (device_ctx.grid.get_num_layers() > 1) {
VPR_FATAL_ERROR(VPR_ERROR_PACK, "Legalizer currently only supports single layer devices.\n");
}

// load and legalize flat placement file, print .net and fix clusters files
bool status = load_flat_placement(vpr_setup, arch);
if (!status) {
return status;
}

// echo flat placement (orphan clusters will have -1 for X, Y, subtile coordinates)
if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_FLAT_PLACE)) {
print_flat_placement(getEchoFileName(E_ECHO_FLAT_PLACE));
}

// reset the device grid
device_ctx.grid.clear();

// if running placement, use the fix clusters file produced by the legalizer
if (vpr_setup.PlacerOpts.doPlacement) {
vpr_setup.PlacerOpts.constraints_file = vpr_setup.FileNameOpts.write_constraints_file;
}
return true;
}

bool vpr_place_flow(const Netlist<>& net_list, t_vpr_setup& vpr_setup, const t_arch& arch) {
VTR_LOG("\n");
const auto& placer_opts = vpr_setup.PlacerOpts;
Expand Down Expand Up @@ -737,6 +789,13 @@ bool vpr_place_flow(const Netlist<>& net_list, t_vpr_setup& vpr_setup, const t_a
placer_opts.floorplan_num_horizontal_partitions, placer_opts.floorplan_num_vertical_partitions);
}

// Write out a flat placement file if the option is specified
// A flat placement file includes cluster and intra-cluster placement coordinates for
// each primitive and can be used to reconstruct a clustering and placement solution.
if (!filename_opts.write_flat_place_file.empty()) {
print_flat_placement(vpr_setup.FileNameOpts.write_flat_place_file.c_str());
}

return true;
}

Expand Down
Loading

0 comments on commit 95b8fee

Please sign in to comment.