add physical pb_type binding for explicit annotations

This commit is contained in:
tangxifan 2020-01-28 14:27:35 -07:00
parent 82f71e82e8
commit caeb0bfff8
5 changed files with 301 additions and 6 deletions

View File

@ -59,7 +59,7 @@ t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
return nullptr;
}
/* If this is already the last pb_type in the list, this is what we want */
if (i == target_pb_type_names.size() - 1) {
if (i + 1 == target_pb_type_names.size() - 1) {
return cur_pb_type;
}
}
@ -69,7 +69,7 @@ t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
}
/********************************************************************
* This function will identify the physical pb_type for each multi-mode
* This function will identify the physical mode for each multi-mode
* pb_type in VPR pb_type graph by following the explicit definition
* in OpenFPGA architecture XML
*******************************************************************/
@ -153,7 +153,7 @@ void build_vpr_physical_pb_mode_explicit_annotation(const DeviceContext& vpr_dev
/********************************************************************
* This function will recursively visit all the pb_type from the top
* pb_type in the graph and
* infer the physical pb_type for each multi-mode
* infer the physical mode for each multi-mode
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
*
* The following rule is applied:
@ -208,7 +208,7 @@ void rec_infer_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
}
/********************************************************************
* This function will infer the physical pb_type for each multi-mode
* This function will infer the physical mode for each multi-mode
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
*
* The following rule is applied:
@ -313,6 +313,159 @@ void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
}
}
/********************************************************************
* This function aims to make a pair of operating and physical
* pb_types:
* - In addition to pairing the pb_types, it will pair the ports of the pb_types
* - For the ports which are explicited annotated as physical pin mapping
* in the pb_type annotation.
* We will check the port range and create a pair
* - For the ports which are not specified in the pb_type annotation
* we assume their physical ports share the same as the operating ports
* We will try to find a port in the physical pb_type and check the port range
* If found, we will create a pair
* - All the pairs will be updated in vpr_pb_type_annotation
*******************************************************************/
static
bool pair_operating_and_physical_pb_types(t_pb_type* operating_pb_type,
t_pb_type* physical_pb_type,
const PbTypeAnnotation& pb_type_annotation,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* Reach here, we should have valid operating and physical pb_types */
VTR_ASSERT((nullptr != operating_pb_type) && (nullptr != physical_pb_type));
/* Iterate over the ports under the operating pb_type
* For each pin, we will try to find its physical port in the pb_type_annotation
* if not found, we assume that the physical port is the same as the operating pb_port
*/
for (t_port* operating_pb_port : pb_type_ports(operating_pb_type)) {
/* Try to find the port in the pb_type_annotation */
BasicPort expected_physical_pb_port = pb_type_annotation.physical_pb_type_port(std::string(operating_pb_port->name));
if (true == expected_physical_pb_port.get_name().empty()) {
/* Not found, we reset the port information to be consistent as the operating pb_port */
expected_physical_pb_port.set_name(std::string(operating_pb_port->name));
expected_physical_pb_port.set_width(operating_pb_port->num_pins);
}
/* Try to find the expected port in the physical pb_type */
t_port* physical_pb_port = find_pb_type_port(physical_pb_type, expected_physical_pb_port.get_name());
/* Not found, mapping fails */
if (nullptr == physical_pb_port) {
return false;
}
/* If the port range does not match, mapping fails */
if (false == expected_physical_pb_port.contained(BasicPort(physical_pb_port->name, physical_pb_port->num_pins))) {
return false;
}
/* Now, port mapping should succeed, we update the vpr_pb_type_annotation */
vpr_pb_type_annotation.add_physical_pb_port(operating_pb_port, physical_pb_port);
vpr_pb_type_annotation.add_physical_pb_port_range(operating_pb_port, expected_physical_pb_port);
}
/* Now, pb_type mapping should succeed, we update the vpr_pb_type_annotation */
vpr_pb_type_annotation.add_physical_pb_type(operating_pb_type, physical_pb_type);
return true;
}
/********************************************************************
* This function will identify the physical pb_type for each operating
* pb_type in VPR pb_type graph by following the explicit definition
* in OpenFPGA architecture XML
*
* Note:
* - This function should be executed only AFTER the physical mode
* annotation is completed
*******************************************************************/
static
void build_vpr_physical_pb_type_annotation(const DeviceContext& vpr_device_ctx,
const Arch& openfpga_arch,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* Walk through the pb_type annotation stored in the openfpga arch */
for (const PbTypeAnnotation& pb_type_annotation : openfpga_arch.pb_type_annotations) {
/* Since our target is to annotate the operating pb_type tp physical pb_type
* we can skip those annotation only for physical pb_type
*/
if (true == pb_type_annotation.is_physical_pb_type()) {
continue;
}
VTR_ASSERT(true == pb_type_annotation.is_operating_pb_type());
/* Collect the information about the full hierarchy of operating pb_type to be annotated */
std::vector<std::string> target_op_pb_type_names;
std::vector<std::string> target_op_pb_mode_names;
target_op_pb_type_names = pb_type_annotation.operating_parent_pb_type_names();
target_op_pb_type_names.push_back(pb_type_annotation.operating_pb_type_name());
target_op_pb_mode_names = pb_type_annotation.operating_parent_mode_names();
/* Collect the information about the full hierarchy of physical pb_type to be annotated */
std::vector<std::string> target_phy_pb_type_names;
std::vector<std::string> target_phy_pb_mode_names;
target_phy_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
target_phy_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
target_phy_pb_mode_names = pb_type_annotation.physical_parent_mode_names();
/* We must have at least one pb_type in the list */
VTR_ASSERT_SAFE(0 < target_op_pb_type_names.size());
VTR_ASSERT_SAFE(0 < target_phy_pb_type_names.size());
/* Pb type information are located at the logic_block_types in the device context of VPR
* We iterate over the vectors and find the pb_type matches the parent_pb_type_name
*/
bool link_success = false;
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
/* By pass nullptr for pb_type head */
if (nullptr == lb_type.pb_type) {
continue;
}
/* Check the name of the top-level pb_type, if it does not match, we can bypass */
if (target_op_pb_type_names[0] != std::string(lb_type.pb_type->name)) {
continue;
}
/* Match the name in the top-level, we go further to search the operating as well as
* physical pb_types in the graph */
t_pb_type* target_op_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_op_pb_type_names,
target_op_pb_mode_names);
if (nullptr == target_op_pb_type) {
continue;
}
t_pb_type* target_phy_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_phy_pb_type_names,
target_phy_pb_mode_names);
if (nullptr == target_phy_pb_type) {
continue;
}
/* Both operating and physical pb_type have been found,
* we update the annotation by assigning the physical mode
*/
if (true == pair_operating_and_physical_pb_types(target_op_pb_type, target_phy_pb_type,
pb_type_annotation, vpr_pb_type_annotation)) {
/* Give a message */
VTR_LOG("Annotate operating pb_type '%s' to its physical pb_type '%s'\n",
target_op_pb_type->name, target_phy_pb_type->name);
link_success = true;
break;
}
}
if (false == link_success) {
/* Not found, error out! */
VTR_LOG_ERROR("Unable to pair the operating pb_type '%s' to its physical pb_type '%s'!\n",
target_op_pb_type_names.back().c_str(),
target_phy_pb_type_names.back().c_str());
return;
}
}
}
/********************************************************************
* Top-level function to link openfpga architecture to VPR, including:
* - physical pb_type
@ -323,7 +476,7 @@ void link_arch(OpenfpgaContext& openfpga_context) {
vtr::ScopedStartFinishTimer timer("Link OpenFPGA architecture to VPR architecture");
/* Annotate physical pb_type in the VPR pb_type graph */
/* Annotate physical mode to pb_type in the VPR pb_type graph */
build_vpr_physical_pb_mode_explicit_annotation(g_vpr_ctx.device(), openfpga_context.arch(),
openfpga_context.mutable_vpr_pb_type_annotation());
build_vpr_physical_pb_mode_implicit_annotation(g_vpr_ctx.device(),
@ -332,7 +485,9 @@ void link_arch(OpenfpgaContext& openfpga_context) {
check_vpr_physical_pb_mode_annotation(g_vpr_ctx.device(),
openfpga_context.vpr_pb_type_annotation());
/* Annotate idle pb_type in the VPR pb_type graph */
/* Annotate physical pb_types to operating pb_type in the VPR pb_type graph */
build_vpr_physical_pb_type_annotation(g_vpr_ctx.device(), openfpga_context.arch(),
openfpga_context.mutable_vpr_pb_type_annotation());
/* Link physical pb_type to circuit model */

View File

@ -64,4 +64,28 @@ t_pb_type* find_mode_child_pb_type(t_mode* mode, const char* child_name) {
return nullptr;
}
/************************************************************************
* With a given pb_type, provide a list of its ports
************************************************************************/
std::vector<t_port*> pb_type_ports(t_pb_type* pb_type) {
std::vector<t_port*> ports;
for (int i = 0; i < pb_type->num_ports; ++i) {
ports.push_back(&(pb_type->ports[i]));
}
return ports;
}
/************************************************************************
* Find a port for a pb_type with a given name
* If not found, return null pointer
************************************************************************/
t_port* find_pb_type_port(t_pb_type* pb_type, const std::string& port_name) {
for (int i = 0; i < pb_type->num_ports; ++i) {
if (port_name == std::string(pb_type->ports[i].name)) {
return &(pb_type->ports[i]);
}
}
return nullptr;
}
} /* end namespace openfpga */

View File

@ -4,6 +4,7 @@
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "physical_types.h"
/********************************************************************
@ -21,6 +22,10 @@ t_mode* find_pb_type_mode(t_pb_type* pb_type, const char* mode_name);
t_pb_type* find_mode_child_pb_type(t_mode* mode, const char* child_name);
std::vector<t_port*> pb_type_ports(t_pb_type* pb_type);
t_port* find_pb_type_port(t_pb_type* pb_type, const std::string& port_name);
} /* end namespace openfpga */
#endif

View File

@ -27,6 +27,34 @@ t_mode* VprPbTypeAnnotation::physical_mode(t_pb_type* pb_type) const {
return physical_pb_modes_.at(pb_type);
}
t_pb_type* VprPbTypeAnnotation::physical_pb_type(t_pb_type* pb_type) const {
/* Ensure that the pb_type is in the list */
std::map<t_pb_type*, t_pb_type*>::const_iterator it = physical_pb_types_.find(pb_type);
if (it == physical_pb_types_.end()) {
return nullptr;
}
return physical_pb_types_.at(pb_type);
}
t_port* VprPbTypeAnnotation::physical_pb_port(t_port* pb_port) const {
/* Ensure that the pb_type is in the list */
std::map<t_port*, t_port*>::const_iterator it = physical_pb_ports_.find(pb_port);
if (it == physical_pb_ports_.end()) {
return nullptr;
}
return physical_pb_ports_.at(pb_port);
}
BasicPort VprPbTypeAnnotation::physical_pb_port_range(t_port* pb_port) const {
/* Ensure that the pb_type is in the list */
std::map<t_port*, BasicPort>::const_iterator it = physical_pb_port_ranges_.find(pb_port);
if (it == physical_pb_port_ranges_.end()) {
/* Return an invalid port. As such the port width will be 0, which is an invalid value */
return BasicPort();
}
return physical_pb_port_ranges_.at(pb_port);
}
/************************************************************************
* Public mutators
***********************************************************************/
@ -41,4 +69,40 @@ void VprPbTypeAnnotation::add_pb_type_physical_mode(t_pb_type* pb_type, t_mode*
physical_pb_modes_[pb_type] = physical_mode;
}
void VprPbTypeAnnotation::add_physical_pb_type(t_pb_type* operating_pb_type, t_pb_type* physical_pb_type) {
/* Warn any override attempt */
std::map<t_pb_type*, t_pb_type*>::const_iterator it = physical_pb_types_.find(operating_pb_type);
if (it != physical_pb_types_.end()) {
VTR_LOG_WARN("Override the annotation between operating pb_type '%s' and it physical pb_type '%s'!\n",
operating_pb_type->name, physical_pb_type->name);
}
physical_pb_types_[operating_pb_type] = physical_pb_type;
}
void VprPbTypeAnnotation::add_physical_pb_port(t_port* operating_pb_port, t_port* physical_pb_port) {
/* Warn any override attempt */
std::map<t_port*, t_port*>::const_iterator it = physical_pb_ports_.find(operating_pb_port);
if (it != physical_pb_ports_.end()) {
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port '%s'!\n",
operating_pb_port->name, physical_pb_port->name);
}
physical_pb_ports_[operating_pb_port] = physical_pb_port;
}
void VprPbTypeAnnotation::add_physical_pb_port_range(t_port* operating_pb_port, const BasicPort& port_range) {
/* The port range must satify the port width*/
VTR_ASSERT((size_t)operating_pb_port->num_pins == port_range.get_width());
/* Warn any override attempt */
std::map<t_port*, BasicPort>::const_iterator it = physical_pb_port_ranges_.find(operating_pb_port);
if (it != physical_pb_port_ranges_.end()) {
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port range '[%ld:%ld]'!\n",
operating_pb_port->name, port_range.get_lsb(), port_range.get_msb());
}
physical_pb_port_ranges_[operating_pb_port] = port_range;
}
} /* End namespace openfpga*/

View File

@ -10,6 +10,7 @@
#include "physical_types.h"
/* Header from openfpgautil library */
#include "openfpga_port.h"
#include "circuit_library.h"
/* Begin namespace openfpga */
@ -29,13 +30,59 @@ class VprPbTypeAnnotation {
VprPbTypeAnnotation();
public: /* Public accessors */
t_mode* physical_mode(t_pb_type* pb_type) const;
t_pb_type* physical_pb_type(t_pb_type* pb_type) const;
t_port* physical_pb_port(t_port* pb_port) const;
BasicPort physical_pb_port_range(t_port* pb_port) const;
public: /* Public mutators */
void add_pb_type_physical_mode(t_pb_type* pb_type, t_mode* physical_mode);
void add_physical_pb_type(t_pb_type* operating_pb_type, t_pb_type* physical_pb_type);
void add_physical_pb_port(t_port* operating_pb_port, t_port* physical_pb_port);
void add_physical_pb_port_range(t_port* operating_pb_port, const BasicPort& port_range);
private: /* Internal data */
/* Flag about if a pb_type is a physical pb_type */
std::map<t_pb_type*, bool> is_physical_pb_types_;
/* Pair a regular pb_type to its physical pb_type */
std::map<t_pb_type*, t_pb_type*> physical_pb_types_;
/* Pair a physical mode for a pb_type
* Note:
* - the physical mode MUST be a child mode of the pb_type
* - the pb_type MUST be a physical pb_type itself
*/
std::map<t_pb_type*, t_mode*> physical_pb_modes_;
/* Pair a physical pb_type to its circuit model
* Note:
* - the pb_type MUST be a physical pb_type itself
*/
std::map<t_pb_type*, CircuitModelId> pb_type_circuit_models_;
/* Pair a pb_type to its mode selection bits
* - if the pb_type is a physical pb_type, the mode bits are the default mode
* where the physical pb_type will operate when used
* - if the pb_type is an operating pb_type, the mode bits will be applied
* when the operating pb_type is used by packer
*/
std::map<t_pb_type*, std::vector<bool>> pb_type_mode_bits_;
/* Pair a pb_port to its physical pb_port
* Note:
* - the parent of physical pb_port MUST be a physical pb_type
*/
std::map<t_port*, t_port*> physical_pb_ports_;
/* Pair a pb_port to its LSB and MSB of a physical pb_port
* Note:
* - the LSB and MSB MUST be in range of the physical pb_port
*/
std::map<t_port*, BasicPort> physical_pb_port_ranges_;
/* Pair a pb_graph_node to a physical pb_graph_node
* Note:
* - the pb_type of physical pb_graph_node must be a physical pb_type
*/
std::map<t_pb_graph_node*, t_pb_graph_node*> physical_pb_graph_nodes_;
};
} /* End namespace openfpga*/