add physical pb data structure and basic allocator

This commit is contained in:
tangxifan 2020-02-21 17:47:27 -07:00
parent b035b4c87f
commit 12f2888c7c
8 changed files with 376 additions and 0 deletions

View File

@ -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*/

View File

@ -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<ClusterBlockId, std::map<int, ClusterNetId>> net_names_;
std::map<t_pb*, AtomNetlist::TruthTable> block_truth_tables_;
/* Link clustered blocks to physical pb (mapping results) */
std::map<ClusterBlockId, PhysicalPb> physical_pbs_;
};
} /* End namespace openfpga*/

View File

@ -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<const t_pb_graph_node*, PhysicalPbId>::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 */

View File

@ -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<PhysicalPbId, PhysicalPbId>::const_iterator physical_pb_iterator;
typedef vtr::Range<physical_pb_iterator> 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<PhysicalPbId, PhysicalPbId> pb_ids_;
vtr::vector<PhysicalPbId, const t_pb_graph_node*> pb_graph_nodes_;
vtr::vector<PhysicalPbId, std::string> names_;
vtr::vector<PhysicalPbId, std::vector<AtomBlockId>> mapped_atoms_;
/* Child pbs are organized as [0..num_child_pb_types-1][0..child_pb_type->num_pb-1] */
vtr::vector<PhysicalPbId, std::map<const t_pb_type*, std::vector<PhysicalPbId>>> child_pbs_;
vtr::vector<PhysicalPbId, PhysicalPbId> parent_pbs_;
vtr::vector<PhysicalPbId, std::vector<size_t>> mode_bits_;
/* Fast lookup */
std::map<const t_pb_graph_node*, PhysicalPbId> type2id_map_;
};
} /* End namespace openfpga*/
#endif

View File

@ -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<physical_pb_id_tag> PhysicalPbId;
class PhysicalPb;
} /* end namespace openfpga */
#endif

View File

@ -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");
}

View File

@ -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 */

View File

@ -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 <vector>
#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