From 12f2888c7c063038ee06d34dee12cda0e219c187 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Feb 2020 17:47:27 -0700 Subject: [PATCH] add physical pb data structure and basic allocator --- .../annotation/vpr_clustering_annotation.cpp | 20 +++ .../annotation/vpr_clustering_annotation.h | 7 ++ openfpga/src/repack/physical_pb.cpp | 96 ++++++++++++++ openfpga/src/repack/physical_pb.h | 71 +++++++++++ openfpga/src/repack/physical_pb_fwd.h | 23 ++++ openfpga/src/repack/repack.cpp | 9 ++ openfpga/src/utils/physical_pb_utils.cpp | 119 ++++++++++++++++++ openfpga/src/utils/physical_pb_utils.h | 31 +++++ 8 files changed, 376 insertions(+) create mode 100644 openfpga/src/repack/physical_pb.cpp create mode 100644 openfpga/src/repack/physical_pb.h create mode 100644 openfpga/src/repack/physical_pb_fwd.h create mode 100644 openfpga/src/utils/physical_pb_utils.cpp create mode 100644 openfpga/src/utils/physical_pb_utils.h diff --git a/openfpga/src/annotation/vpr_clustering_annotation.cpp b/openfpga/src/annotation/vpr_clustering_annotation.cpp index cd32fdeac..e0c7ab575 100644 --- a/openfpga/src/annotation/vpr_clustering_annotation.cpp +++ b/openfpga/src/annotation/vpr_clustering_annotation.cpp @@ -41,6 +41,14 @@ AtomNetlist::TruthTable VprClusteringAnnotation::truth_table(t_pb* pb) const { return block_truth_tables_.at(pb); } +PhysicalPb VprClusteringAnnotation::physical_pb(const ClusterBlockId& block_id) const { + if (physical_pbs_.end() == physical_pbs_.find(block_id)) { + return PhysicalPb(); + } + + return physical_pbs_.at(block_id); +} + /************************************************************************ * Public mutators ***********************************************************************/ @@ -67,4 +75,16 @@ void VprClusteringAnnotation::adapt_truth_table(t_pb* pb, block_truth_tables_[pb] = tt; } +void VprClusteringAnnotation::add_physical_pb(const ClusterBlockId& block_id, + const PhysicalPb& physical_pb) { + /* Warn any override attempt */ + if (physical_pbs_.end() != physical_pbs_.find(block_id)) { + VTR_LOG_WARN("Override the physical pb for clustered block %lu in clustering context annotation!\n", + size_t(block_id)); + } + + physical_pbs_[block_id] = physical_pb; +} + + } /* End namespace openfpga*/ diff --git a/openfpga/src/annotation/vpr_clustering_annotation.h b/openfpga/src/annotation/vpr_clustering_annotation.h index 2951ef226..b72173e1d 100644 --- a/openfpga/src/annotation/vpr_clustering_annotation.h +++ b/openfpga/src/annotation/vpr_clustering_annotation.h @@ -9,6 +9,8 @@ /* Header from vpr library */ #include "clustered_netlist.h" +#include "physical_pb.h" + /* Begin namespace openfpga */ namespace openfpga { @@ -33,14 +35,19 @@ class VprClusteringAnnotation { ClusterNetId net(const ClusterBlockId& block_id, const int& pin_index) const; bool is_truth_table_adapted(t_pb* pb) const; AtomNetlist::TruthTable truth_table(t_pb* pb) const; + PhysicalPb physical_pb(const ClusterBlockId& block_id) const; public: /* Public mutators */ void rename_net(const ClusterBlockId& block_id, const int& pin_index, const ClusterNetId& net_id); void adapt_truth_table(t_pb* pb, const AtomNetlist::TruthTable& tt); + void add_physical_pb(const ClusterBlockId& block_id, const PhysicalPb& physical_pb); private: /* Internal data */ /* Pair a regular pb_type to its physical pb_type */ std::map> net_names_; std::map block_truth_tables_; + + /* Link clustered blocks to physical pb (mapping results) */ + std::map physical_pbs_; }; } /* End namespace openfpga*/ diff --git a/openfpga/src/repack/physical_pb.cpp b/openfpga/src/repack/physical_pb.cpp new file mode 100644 index 000000000..1b3760dcc --- /dev/null +++ b/openfpga/src/repack/physical_pb.cpp @@ -0,0 +1,96 @@ +/****************************************************************************** + * Memember functions for data structure PhysicalPb + ******************************************************************************/ +#include "vtr_assert.h" +#include "vtr_log.h" + +#include "physical_pb.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/************************************************** + * Public Accessors + *************************************************/ +PhysicalPb::physical_pb_range PhysicalPb::pbs() const { + return vtr::make_range(pb_ids_.begin(), pb_ids_.end()); +} + +std::string PhysicalPb::name(const PhysicalPbId& pb) const { + VTR_ASSERT(true == valid_pb_id(pb)); + return names_[pb]; +} + +/* Find the module id by a given name, return invalid if not found */ +PhysicalPbId PhysicalPb::find_pb(const t_pb_graph_node* pb_graph_node) const { + if (type2id_map_.find(pb_graph_node) != type2id_map_.end()) { + /* Find it, return the id */ + return type2id_map_.at(pb_graph_node); + } + /* Not found, return an invalid id */ + return PhysicalPbId::INVALID(); +} + +PhysicalPbId PhysicalPb::parent(const PhysicalPbId& pb) const { + VTR_ASSERT(true == valid_pb_id(pb)); + return parent_pbs_[pb]; +} + +/****************************************************************************** + * Private Mutators + ******************************************************************************/ +PhysicalPbId PhysicalPb::create_pb(const t_pb_graph_node* pb_graph_node) { + /* Find if the name has been used. If used, return an invalid Id and report error! */ + std::map::iterator it = type2id_map_.find(pb_graph_node); + if (it != type2id_map_.end()) { + return PhysicalPbId::INVALID(); + } + + /* Create an new id */ + PhysicalPbId pb = PhysicalPbId(pb_ids_.size()); + pb_ids_.push_back(pb); + + /* Allocate other attributes */ + names_.emplace_back(); + pb_graph_nodes_.push_back(pb_graph_node); + mapped_atoms_.emplace_back(); + child_pbs_.emplace_back(); + parent_pbs_.emplace_back(); + mode_bits_.emplace_back(); + + /* Register in the name2id map */ + type2id_map_[pb_graph_node] = pb; + + return pb; +} + +void PhysicalPb::add_child(const PhysicalPbId& parent, + const PhysicalPbId& child, + const t_pb_type* child_type) { + VTR_ASSERT(true == valid_pb_id(parent)); + VTR_ASSERT(true == valid_pb_id(child)); + + child_pbs_[parent][child_type].push_back(child); + + if (PhysicalPbId::INVALID() != parent_pbs_[child]) { + VTR_LOGF_WARN(__FILE__, __LINE__, + "Overwrite parent '%s' for physical pb '%s' with a new one '%s'!\n", + pb_graph_nodes_[parent_pbs_[child]]->hierarchical_type_name().c_str(), + pb_graph_nodes_[child]->hierarchical_type_name().c_str(), + pb_graph_nodes_[parent]->hierarchical_type_name().c_str()); + } + parent_pbs_[child] = parent; +} + +/****************************************************************************** + * Private validators/invalidators + ******************************************************************************/ +bool PhysicalPb::valid_pb_id(const PhysicalPbId& pb_id) const { + return ( size_t(pb_id) < pb_ids_.size() ) && ( pb_id == pb_ids_[pb_id] ); +} + +bool PhysicalPb::empty() const { + return 0 == pb_ids_.size(); +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/repack/physical_pb.h b/openfpga/src/repack/physical_pb.h new file mode 100644 index 000000000..8a9d3b20d --- /dev/null +++ b/openfpga/src/repack/physical_pb.h @@ -0,0 +1,71 @@ +#ifndef PHYSICAL_PB_H +#define PHYSICAL_PB_H + +/******************************************************************** + * Include header files required by the data structure definition + *******************************************************************/ +/* Headers from vtrutil library */ +#include "vtr_geometry.h" +#include "vtr_vector.h" + +/* Headers from readarch library */ +#include "physical_types.h" + +/* Headers from vpr library */ +#include "atom_netlist_fwd.h" + +#include "physical_pb_fwd.h" + +/* Begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * PhysicalPb object aims to store the mapped result for a programmable + * logical block like the VPR data structure t_pb does. + * Differently, it is tailored for the physical implementation of a + * programmable block. + * - It does not contain multi-mode for each child physical_pb while + * VPR t_pb does have multi-mode. This is because that the hardware + * implementation is unique + * - It contains mode-selection bits for each primitive physical_pb + * This is used to help bitstream generator to configure a primitive + * circuit in the correct mode + * - A primitive LUT can be mapped to various truth tables. + * This is true for any fracturable LUTs. + *******************************************************************/ +class PhysicalPb { + public: /* Types and ranges */ + typedef vtr::vector::const_iterator physical_pb_iterator; + typedef vtr::Range physical_pb_range; + public: /* Public aggregators */ + physical_pb_range pbs() const; + std::string name(const PhysicalPbId& pb) const; + PhysicalPbId find_pb(const t_pb_graph_node* name) const; + PhysicalPbId parent(const PhysicalPbId& pb) const; + public: /* Public mutators */ + PhysicalPbId create_pb(const t_pb_graph_node* pb_graph_node); + void add_child(const PhysicalPbId& parent, + const PhysicalPbId& child, + const t_pb_type* child_type); + public: /* Public validators/invalidators */ + bool valid_pb_id(const PhysicalPbId& pb_id) const; + bool empty() const; + private: /* Internal Data */ + vtr::vector pb_ids_; + vtr::vector pb_graph_nodes_; + vtr::vector names_; + vtr::vector> mapped_atoms_; + + /* Child pbs are organized as [0..num_child_pb_types-1][0..child_pb_type->num_pb-1] */ + vtr::vector>> child_pbs_; + vtr::vector parent_pbs_; + + vtr::vector> mode_bits_; + + /* Fast lookup */ + std::map type2id_map_; +}; + +} /* End namespace openfpga*/ + +#endif diff --git a/openfpga/src/repack/physical_pb_fwd.h b/openfpga/src/repack/physical_pb_fwd.h new file mode 100644 index 000000000..d601ab060 --- /dev/null +++ b/openfpga/src/repack/physical_pb_fwd.h @@ -0,0 +1,23 @@ +/************************************************** + * This file includes only declarations for + * the data structures for PhysicalPb + * Please refer to physical_pb.h for more details + *************************************************/ +#ifndef PHYSICAL_PB_FWD_H +#define PHYSICAL_PB_FWD_H + +#include "vtr_strong_id.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/* Strong Ids for ModuleManager */ +struct physical_pb_id_tag; + +typedef vtr::StrongId PhysicalPbId; + +class PhysicalPb; + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/repack/repack.cpp b/openfpga/src/repack/repack.cpp index e554a63ed..578efd91f 100644 --- a/openfpga/src/repack/repack.cpp +++ b/openfpga/src/repack/repack.cpp @@ -14,6 +14,7 @@ #include "build_physical_lb_rr_graph.h" #include "lb_router.h" #include "lb_router_utils.h" +#include "physical_pb_utils.h" #include "repack.h" /* begin namespace openfpga */ @@ -284,6 +285,14 @@ void repack_cluster(const DeviceContext& device_ctx, VTR_ASSERT(true == route_success); VTR_LOGV(verbose, "Reroute succeed\n"); + /* Annotate routing results to physical pb */ + PhysicalPb phy_pb; + alloc_physical_pb_from_pb_graph(phy_pb, pb_graph_head, device_annotation); + rec_update_physical_pb_from_operating_pb(phy_pb, clustering_ctx.clb_nlist.block_pb(block_id)); + + /* Add the pb to clustering context */ + clustering_annotation.add_physical_pb(block_id, phy_pb); + VTR_LOG("Done\n"); } diff --git a/openfpga/src/utils/physical_pb_utils.cpp b/openfpga/src/utils/physical_pb_utils.cpp new file mode 100644 index 000000000..9502df674 --- /dev/null +++ b/openfpga/src/utils/physical_pb_utils.cpp @@ -0,0 +1,119 @@ +/************************************************************************ + * Function to perform fundamental operation for the physical pb using + * data structures + ***********************************************************************/ +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" + +#include "openfpga_naming.h" +#include "pb_type_utils.h" +#include "physical_pb_utils.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/************************************************************************ + * Allocate an empty physical pb graph based on pb_graph + * This function should start with an empty physical pb object!!! + * Suggest to check this before executing this function + * VTR_ASSERT(true == phy_pb.empty()); + ***********************************************************************/ +static +void rec_alloc_physical_pb_from_pb_graph(PhysicalPb& phy_pb, + t_pb_graph_node* pb_graph_node, + const VprDeviceAnnotation& device_annotation) { + t_pb_type* pb_type = pb_graph_node->pb_type; + + t_mode* physical_mode = device_annotation.physical_mode(pb_type); + + PhysicalPbId cur_phy_pb_id = phy_pb.create_pb(pb_graph_node); + VTR_ASSERT(true == phy_pb.valid_pb_id(cur_phy_pb_id)); + + /* Finish for primitive node */ + if (true == is_primitive_pb_type(pb_type)) { + return; + } + + /* Find the physical mode */ + VTR_ASSERT(nullptr != physical_mode); + + /* Go to the leaf nodes first. This aims to build all the primitive nodes first + * and then we build the parents and create links + */ + for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) { + for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) { + rec_alloc_physical_pb_from_pb_graph(phy_pb, + &(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][jpb]), + device_annotation); + } + } +} + +/************************************************************************ + * Build all the relationships between parent and children + * inside a physical pb graph + * This function must be executed after rec_alloc_physical_pb_from_pb_graph()!!! + ***********************************************************************/ +static +void rec_build_physical_pb_children_from_pb_graph(PhysicalPb& phy_pb, + t_pb_graph_node* pb_graph_node, + const VprDeviceAnnotation& device_annotation) { + t_pb_type* pb_type = pb_graph_node->pb_type; + + /* Finish for primitive node */ + if (true == is_primitive_pb_type(pb_type)) { + return; + } + + t_mode* physical_mode = device_annotation.physical_mode(pb_type); + VTR_ASSERT(nullptr != physical_mode); + + /* Please use the openfpga naming function so that you can build the link to module manager */ + PhysicalPbId parent_pb_id = phy_pb.find_pb(pb_graph_node); + VTR_ASSERT(true == phy_pb.valid_pb_id(parent_pb_id)); + + /* Add all the children */ + for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) { + for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) { + PhysicalPbId child_pb_id = phy_pb.find_pb(&(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][jpb])); + VTR_ASSERT(true == phy_pb.valid_pb_id(child_pb_id)); + phy_pb.add_child(parent_pb_id, child_pb_id, &(physical_mode->pb_type_children[ipb])); + } + } + + /* Go to the leaf nodes first. This aims to build all the primitive nodes first + * and then we build the parents and create links + */ + for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) { + for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) { + rec_build_physical_pb_children_from_pb_graph(phy_pb, + &(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][jpb]), + device_annotation); + } + } +} + +/************************************************************************ + * Allocate an empty physical pb graph based on pb_graph + * This function should start with an empty physical pb object!!! + * Suggest to check this before executing this function + * VTR_ASSERT(true == phy_pb.empty()); + ***********************************************************************/ +void alloc_physical_pb_from_pb_graph(PhysicalPb& phy_pb, + t_pb_graph_node* pb_graph_head, + const VprDeviceAnnotation& device_annotation) { + VTR_ASSERT(true == phy_pb.empty()); + + rec_alloc_physical_pb_from_pb_graph(phy_pb, pb_graph_head, device_annotation); + rec_build_physical_pb_children_from_pb_graph(phy_pb, pb_graph_head, device_annotation); +} + +/************************************************************************ + * Synchronize mapping results from an operating pb to a physical pb + ***********************************************************************/ +void rec_update_physical_pb_from_operating_pb(PhysicalPb& phy_pb, + t_pb* op_pb) { +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/utils/physical_pb_utils.h b/openfpga/src/utils/physical_pb_utils.h new file mode 100644 index 000000000..bdd37dc81 --- /dev/null +++ b/openfpga/src/utils/physical_pb_utils.h @@ -0,0 +1,31 @@ +/******************************************************************** + * Header file for circuit_library_utils.cpp + *******************************************************************/ +#ifndef PHYSICAL_PB_UTILS_H +#define PHYSICAL_PB_UTILS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include "physical_types.h" +#include "vpr_device_annotation.h" +#include "physical_pb.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void alloc_physical_pb_from_pb_graph(PhysicalPb& phy_pb, + t_pb_graph_node* pb_graph_head, + const VprDeviceAnnotation& device_annotation); + +void rec_update_physical_pb_from_operating_pb(PhysicalPb& phy_pb, + t_pb* op_pb); + +} /* end namespace openfpga */ + +#endif