add physical pb data structure and basic allocator
This commit is contained in:
parent
b035b4c87f
commit
12f2888c7c
|
@ -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*/
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
Loading…
Reference in New Issue