Merge branch 'refactoring' into dev

This commit is contained in:
tangxifan 2020-01-28 21:59:57 -07:00
commit bfaa2442a2
15 changed files with 1630 additions and 320 deletions

View File

@ -162,7 +162,8 @@ enum e_pin_type {
enum e_interconnect {
COMPLETE_INTERC = 1,
DIRECT_INTERC = 2,
MUX_INTERC = 3
MUX_INTERC = 3,
NUM_INTERC_TYPES
};
/* Orientations. */

View File

@ -0,0 +1,122 @@
/********************************************************************
* This file includes functions that are used to annotate pb_graph_node
* and pb_graph_pins from VPR to OpenFPGA
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "pb_type_utils.h"
#include "pb_graph_utils.h"
#include "annotate_pb_graph.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* This function will recursively walk through all the pb_graph nodes
* starting from a top node.
* It aims to annotate the physical type of each interconnect.
* This is due to that the type of interconnect 'complete' may diverge
* in physical implmentation.
* - When there is only one input driving a 'complete' interconnection,
* it will be implemented with wires
* - When there are multiple inputs driving a 'complete' interconnection,
* it will be implemented with routing multiplexers
*******************************************************************/
static
void rec_build_vpr_pb_graph_interconnect_physical_type_annotation(t_pb_graph_node* pb_graph_node,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* Skip the root node because we start from the inputs of child pb_graph node
*
* pb_graph_node
* +----------------------------------
* | child_pb_graph_node
* | +-----------------
* | |
* |-------------+-->input_pins
* | |
* |-------------+-->clock_pins
* |
*
*/
if (false == pb_graph_node->is_root()) {
/* We only care the physical modes! But we have to find it through the parent node */
t_mode* child_physical_mode = vpr_pb_type_annotation.physical_mode(pb_graph_node->parent_pb_graph_node->pb_type);
VTR_ASSERT(nullptr != child_physical_mode);
std::map<t_interconnect*, size_t> interc_num_inputs;
/* Initialize the counter */
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
interc_num_inputs[interc] = 0;
}
/* We only care input and clock pins */
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
/* For each interconnect, we count the total number of inputs */
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
interc_num_inputs[interc] += pb_graph_pin_inputs(&(pb_graph_node->input_pins[iport][ipin]), interc).size();
}
}
}
for (int iport = 0; iport < pb_graph_node->num_clock_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_clock_pins[iport]; ++ipin) {
/* For each interconnect, we count the total number of inputs */
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
interc_num_inputs[interc] += pb_graph_pin_inputs(&(pb_graph_node->clock_pins[iport][ipin]), interc).size();
}
}
}
/* For each interconnect that has more than 1 input, we can infer the physical type */
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
e_interconnect interc_physical_type = pb_interconnect_physical_type(interc, interc_num_inputs[interc]);
if (interc_physical_type == vpr_pb_type_annotation.interconnect_physical_type(interc)) {
/* Skip annotation if we have already done! */
continue;
}
vpr_pb_type_annotation.add_interconnect_physical_type(interc, interc_physical_type);
}
}
/* If we reach a primitive pb_graph node, we return */
if (true == is_primitive_pb_type(pb_graph_node->pb_type)) {
return;
}
/* Recursively visit all the child pb_graph_nodes */
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(pb_graph_node->pb_type);
VTR_ASSERT(nullptr != physical_mode);
for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) {
/* Each child may exist multiple times in the hierarchy*/
for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) {
rec_build_vpr_pb_graph_interconnect_physical_type_annotation(&(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][jpb]), vpr_pb_type_annotation);
}
}
}
/********************************************************************
* This function aims to annotate the physical type for each interconnect
* inside the pb_graph
*
* Note:
* - This function should be executed AFTER functions
* build_vpr_physical_pb_mode_explicit_annotation()
* build_vpr_physical_pb_mode_implicit_annotation()
*******************************************************************/
void annotate_pb_graph_interconnect_physical_type(const DeviceContext& vpr_device_ctx,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
/* By pass nullptr for pb_graph head */
if (nullptr == lb_type.pb_graph_head) {
continue;
}
rec_build_vpr_pb_graph_interconnect_physical_type_annotation(lb_type.pb_graph_head, vpr_pb_type_annotation);
}
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef ANNOTATE_PB_GRAPH_H
#define ANNOTATE_PB_GRAPH_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "openfpga_context.h"
#include "vpr_pb_type_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void annotate_pb_graph_interconnect_physical_type(const DeviceContext& vpr_device_ctx,
VprPbTypeAnnotation& vpr_pb_type_annotation);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,985 @@
/********************************************************************
* This file includes functions to build links between pb_types
* in particular to annotate the physical mode and physical pb_type
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_time.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vpr_pb_type_annotation.h"
#include "pb_type_utils.h"
#include "annotate_pb_graph.h"
#include "annotate_pb_types.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* 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
*******************************************************************/
static
void build_vpr_physical_pb_mode_explicit_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 physical mode name,
* we can skip those has not physical mode defined
*/
if (true == pb_type_annotation.physical_mode_name().empty()) {
continue;
}
/* Identify if the pb_type is operating or physical,
* For operating pb_type, get the full name of operating pb_type
* For physical pb_type, get the full name of physical pb_type
*/
std::vector<std::string> target_pb_type_names;
std::vector<std::string> target_pb_mode_names;
if (true == pb_type_annotation.is_operating_pb_type()) {
target_pb_type_names = pb_type_annotation.operating_parent_pb_type_names();
target_pb_type_names.push_back(pb_type_annotation.operating_pb_type_name());
target_pb_mode_names = pb_type_annotation.operating_parent_mode_names();
}
if (true == pb_type_annotation.is_physical_pb_type()) {
target_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
target_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
target_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_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_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 pb_type in the graph */
t_pb_type* target_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_pb_type_names,
target_pb_mode_names);
if (nullptr == target_pb_type) {
continue;
}
/* Found, we update the annotation by assigning the physical mode */
t_mode* physical_mode = find_pb_type_mode(target_pb_type, pb_type_annotation.physical_mode_name().c_str());
vpr_pb_type_annotation.add_pb_type_physical_mode(target_pb_type, physical_mode);
/* Give a message */
VTR_LOG("Annotate pb_type '%s' with physical mode '%s'\n",
target_pb_type->name, physical_mode->name);
link_success = true;
break;
}
if (false == link_success) {
/* Not found, error out! */
VTR_LOG_ERROR("Unable to find the pb_type '%s' in VPR architecture definition!\n",
target_pb_type_names.back().c_str());
return;
}
}
}
/********************************************************************
* This function will recursively visit all the pb_type from the top
* pb_type in the graph and
* infer the physical mode for each multi-mode
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
*
* The following rule is applied:
* if there is only 1 mode under a pb_type, it will be the default
* physical mode for this pb_type
*******************************************************************/
static
void rec_infer_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* We do not check any primitive pb_type */
if (true == is_primitive_pb_type(cur_pb_type)) {
return;
}
/* For non-primitive pb_type:
* - if there is only one mode, it will be the physical mode
* we just need to make sure that we do not repeatedly annotate this
* - if there are multiple modes, we should be able to find a physical mode
* and then go recursively
*/
t_mode* physical_mode = nullptr;
if (1 == cur_pb_type->num_modes) {
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
/* Not assigned by explicit annotation, we should infer here */
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
VTR_LOG("Implicitly infer physical mode '%s' for pb_type '%s'\n",
cur_pb_type->modes[0].name, cur_pb_type->name);
}
} else {
VTR_ASSERT(1 < cur_pb_type->num_modes);
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
/* Not assigned by explicit annotation, we should infer here */
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
cur_pb_type->name);
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
return;
}
}
/* Get the physical mode from annotation */
physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
VTR_ASSERT(nullptr != physical_mode);
/* Traverse the pb_type children under the physical mode */
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
rec_infer_vpr_physical_pb_mode_annotation(&(physical_mode->pb_type_children[ichild]),
vpr_pb_type_annotation);
}
}
/********************************************************************
* 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:
* if there is only 1 mode under a pb_type, it will be the default
* physical mode for this pb_type
*
* Note:
* This function must be executed AFTER the function
* build_vpr_physical_pb_mode_explicit_annotation()
*******************************************************************/
static
void build_vpr_physical_pb_mode_implicit_annotation(const DeviceContext& vpr_device_ctx,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
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;
}
rec_infer_vpr_physical_pb_mode_annotation(lb_type.pb_type, vpr_pb_type_annotation);
}
}
/********************************************************************
* This function will recursively traverse pb_type graph to ensure
* 1. there is only a physical mode under each pb_type
* 2. physical mode appears only when its parent is a physical mode.
*******************************************************************/
static
void rec_check_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
const bool& expect_physical_mode,
const VprPbTypeAnnotation& vpr_pb_type_annotation,
size_t& num_err) {
/* We do not check any primitive pb_type */
if (true == is_primitive_pb_type(cur_pb_type)) {
return;
}
/* For non-primitive pb_type:
* - If we expect a physical mode to exist under this pb_type
* we should be able to find one in the annoation
* - If we do NOT expect a physical mode, make sure we find
* nothing in the annotation
*/
if (true == expect_physical_mode) {
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
cur_pb_type->name);
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
num_err++;
return;
}
} else {
VTR_ASSERT_SAFE(false == expect_physical_mode);
if (nullptr != vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
VTR_LOG_ERROR("Find a physical mode '%s' for pb_type '%s' which is not under any physical mode!\n",
vpr_pb_type_annotation.physical_mode(cur_pb_type)->name,
cur_pb_type->name);
num_err++;
return;
}
}
/* Traverse all the modes
* - for pb_type children under a physical mode, we expect an physical mode
* - for pb_type children under non-physical mode, we expect no physical mode
*/
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
bool expect_child_physical_mode = false;
if (&(cur_pb_type->modes[imode]) == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
expect_child_physical_mode = true && expect_physical_mode;
}
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
rec_check_vpr_physical_pb_mode_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
expect_child_physical_mode, vpr_pb_type_annotation,
num_err);
}
}
}
/********************************************************************
* This function will check the physical mode annotation for
* each pb_type in the device
*******************************************************************/
static
void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
size_t num_err = 0;
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;
}
/* Top pb_type should always has a physical mode! */
rec_check_vpr_physical_pb_mode_annotation(lb_type.pb_type, true, vpr_pb_type_annotation, num_err);
}
if (0 == num_err) {
VTR_LOG("Check physical mode annotation for pb_types passed.\n");
} else {
VTR_LOG("Check physical mode annotation for pb_types failed with %ld errors!\n",
num_err);
}
}
/********************************************************************
* 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_explicit_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;
}
}
}
/********************************************************************
* This function aims to pair a physical pb_type to itself
*******************************************************************/
static
bool self_pair_physical_pb_types(t_pb_type* physical_pb_type,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* Reach here, we should have valid physical pb_types */
VTR_ASSERT(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* physical_pb_port : pb_type_ports(physical_pb_type)) {
BasicPort physical_port_range(physical_pb_port->name, physical_pb_port->num_pins);
vpr_pb_type_annotation.add_physical_pb_port(physical_pb_port, physical_pb_port);
vpr_pb_type_annotation.add_physical_pb_port_range(physical_pb_port, physical_port_range);
}
/* Now, pb_type mapping should succeed, we update the vpr_pb_type_annotation */
vpr_pb_type_annotation.add_physical_pb_type(physical_pb_type, physical_pb_type);
return true;
}
/********************************************************************
* This function will recursively visit all the pb_type from the top
* pb_type in the graph (only in the physical mode) and infer the
* physical pb_type
* This is mainly applied to single-mode pb_type graphs, where the
* physical pb_type should be pb_type itself
* We can infer this and save the explicit annotation required by users
*******************************************************************/
static
void rec_infer_vpr_physical_pb_type_annotation(t_pb_type* cur_pb_type,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* Physical pb_type is mainly for the primitive pb_type */
if (true == is_primitive_pb_type(cur_pb_type)) {
/* If the physical pb_type has been mapped, we can skip it */
if (nullptr != vpr_pb_type_annotation.physical_pb_type(cur_pb_type)) {
return;
}
/* Create the pair here */
if (true == self_pair_physical_pb_types(cur_pb_type, vpr_pb_type_annotation)) {
/* Give a message */
VTR_LOG("Implicitly infer the physical pb_type for pb_type '%s' itself\n",
cur_pb_type->name);
} else {
VTR_LOG_ERROR("Unable to infer the physical pb_type for pb_type '%s' itself!\n",
cur_pb_type->name);
}
return;
}
/* Get the physical mode from annotation */
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
VTR_ASSERT(nullptr != physical_mode);
/* Traverse the pb_type children under the physical mode */
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
rec_infer_vpr_physical_pb_type_annotation(&(physical_mode->pb_type_children[ichild]),
vpr_pb_type_annotation);
}
}
/********************************************************************
* This function will infer the physical pb_type for each operating
* pb_type in VPR pb_type graph which have not been explicitedly defined
* 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_implicit_annotation(const DeviceContext& vpr_device_ctx,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
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;
}
rec_infer_vpr_physical_pb_type_annotation(lb_type.pb_type, vpr_pb_type_annotation);
}
}
/********************************************************************
* This function will check
* - if a primitive pb_type has been mapped to a physical pb_type
* - if every port of the pb_type have been linked a port of a physical pb_type
*******************************************************************/
static
void check_vpr_physical_primitive_pb_type_annotation(t_pb_type* cur_pb_type,
const VprPbTypeAnnotation& vpr_pb_type_annotation,
size_t& num_err) {
if (nullptr == vpr_pb_type_annotation.physical_pb_type(cur_pb_type)) {
VTR_LOG_ERROR("Find a pb_type '%s' which has not been mapped to any physical pb_type!\n",
cur_pb_type->name);
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
num_err++;
return;
}
/* Now we need to check each port of the pb_type */
for (t_port* pb_port : pb_type_ports(cur_pb_type)) {
if (nullptr == vpr_pb_type_annotation.physical_pb_port(pb_port)) {
VTR_LOG_ERROR("Find a port '%s' of pb_type '%s' which has not been mapped to any physical port!\n",
pb_port->name, cur_pb_type->name);
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
num_err++;
}
}
return;
}
/********************************************************************
* This function will recursively traverse pb_type graph to ensure
* 1. there is only a physical mode under each pb_type
* 2. physical mode appears only when its parent is a physical mode.
*******************************************************************/
static
void rec_check_vpr_physical_pb_type_annotation(t_pb_type* cur_pb_type,
const VprPbTypeAnnotation& vpr_pb_type_annotation,
size_t& num_err) {
/* Primitive pb_type should always been binded to a physical pb_type */
if (true == is_primitive_pb_type(cur_pb_type)) {
check_vpr_physical_primitive_pb_type_annotation(cur_pb_type, vpr_pb_type_annotation, num_err);
return;
}
/* Traverse all the modes
* - for pb_type children under a physical mode, we expect an physical mode
* - for pb_type children under non-physical mode, we expect no physical mode
*/
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
rec_check_vpr_physical_pb_type_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
vpr_pb_type_annotation,
num_err);
}
}
}
/********************************************************************
* This function will check the physical pb_type annotation for
* each pb_type in the device
* Every pb_type should have been linked to a physical pb_type
* and every port of the pb_type have been linked a port of a physical pb_type
*******************************************************************/
static
void check_vpr_physical_pb_type_annotation(const DeviceContext& vpr_device_ctx,
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
size_t num_err = 0;
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;
}
/* Top pb_type should always has a physical mode! */
rec_check_vpr_physical_pb_type_annotation(lb_type.pb_type, vpr_pb_type_annotation, num_err);
}
if (0 == num_err) {
VTR_LOG("Check physical pb_type annotation for pb_types passed.\n");
} else {
VTR_LOG("Check physical pb_type annotation for pb_types failed with %ld errors!\n",
num_err);
}
}
/********************************************************************
* This function aims to link a physical pb_type to a valid circuit model
* in the circuit library
*******************************************************************/
static
bool link_physical_pb_type_to_circuit_model(t_pb_type* physical_pb_type,
const CircuitLibrary& circuit_lib,
const PbTypeAnnotation& pb_type_annotation,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* Reach here, we should have valid operating and physical pb_types */
VTR_ASSERT(nullptr != physical_pb_type);
/* This must be a physical pb_type according to our annotation! */
if (false == vpr_pb_type_annotation.is_physical_pb_type(physical_pb_type)) {
VTR_LOG_ERROR("An operating pb_type '%s' is not allowed to be linked to any circuit model!\n",
physical_pb_type->name);
return false;
}
std::string pb_type_circuit_model_name = pb_type_annotation.circuit_model_name();
CircuitModelId circuit_model_id = circuit_lib.model(pb_type_circuit_model_name);
if (CircuitModelId::INVALID() == circuit_model_id) {
VTR_LOG_ERROR("Unable to find a circuit model '%s' for physical pb_type '%s'!\n",
pb_type_circuit_model_name.c_str(),
physical_pb_type->name);
return false;
}
/* Now the circuit model is valid, update the vpr_pb_type_annotation */
vpr_pb_type_annotation.add_pb_type_circuit_model(physical_pb_type, circuit_model_id);
return true;
}
/********************************************************************
* This function aims to link an interconnect of a physical mode of
* a pb_type to a valid circuit model in the circuit library
*******************************************************************/
static
bool link_physical_pb_interconnect_to_circuit_model(t_pb_type* physical_pb_type,
const std::string& interconnect_name,
const CircuitLibrary& circuit_lib,
const PbTypeAnnotation& pb_type_annotation,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* The physical pb_type should NOT be a primitive, otherwise it should never contain any interconnect */
if (true == is_primitive_pb_type(physical_pb_type)) {
VTR_LOG_ERROR("Link interconnect to circuit model is not allowed for a primitive pb_type '%s'!\n",
physical_pb_type->name);
return false;
}
/* Get the physical mode from annotation */
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(physical_pb_type);
VTR_ASSERT(nullptr != physical_mode);
/* Find the interconnect name under the physical mode of a physical pb_type */
t_interconnect* pb_interc = find_pb_mode_interconnect(physical_mode, interconnect_name.c_str());
if (nullptr == pb_interc) {
VTR_LOG_ERROR("Unable to find interconnect '%s' under physical mode '%s' of pb_type '%s'!\n",
interconnect_name.c_str(),
physical_mode->name,
physical_pb_type->name);
return false;
}
/* Try to find the circuit model name */
std::string pb_type_circuit_model_name = pb_type_annotation.interconnect_circuit_model_name(interconnect_name);
CircuitModelId circuit_model_id = circuit_lib.model(pb_type_circuit_model_name);
if (CircuitModelId::INVALID() == circuit_model_id) {
VTR_LOG_ERROR("Unable to find a circuit model '%s' for interconnect '%s' under physical mode '%s' of pb_type '%s'!\n",
pb_type_circuit_model_name.c_str(),
interconnect_name.c_str(),
physical_mode->name,
physical_pb_type->name);
return false;
}
/* Now the circuit model is valid, update the vpr_pb_type_annotation */
vpr_pb_type_annotation.add_interconnect_circuit_model(pb_interc, circuit_model_id);
VTR_LOG("Bind pb_type '%s' physical mode '%s' interconnect '%s' to circuit model '%s'\n",
physical_pb_type->name,
physical_mode->name,
pb_interc->name,
circuit_lib.model_name(circuit_model_id).c_str());
return true;
}
/********************************************************************
* This function will link
* - pb_type to circuit models in circuit library by following
* the explicit definition in OpenFPGA architecture XML
*
* Note:
* - This function should be executed only AFTER the physical mode and
* physical pb_type annotation is completed
*******************************************************************/
static
void link_vpr_pb_type_to_circuit_model_explicit_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 circuti model for physical pb_type
* we can skip those annotation only for operating pb_type
*/
if (true == pb_type_annotation.is_operating_pb_type()) {
continue;
}
if (true == pb_type_annotation.circuit_model_name().empty()) {
continue;
}
VTR_ASSERT(true == pb_type_annotation.is_physical_pb_type());
/* 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_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_phy_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_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;
}
/* Only try to bind pb_type to circuit model when it is defined by users */
if (true == link_physical_pb_type_to_circuit_model(target_phy_pb_type, openfpga_arch.circuit_lib,
pb_type_annotation, vpr_pb_type_annotation)) {
/* Give a message */
VTR_LOG("Bind physical pb_type '%s' to its circuit model '%s'\n",
target_phy_pb_type->name,
openfpga_arch.circuit_lib.model_name(vpr_pb_type_annotation.pb_type_circuit_model(target_phy_pb_type)).c_str());
link_success = true;
break;
}
}
if (false == link_success) {
/* Not found, error out! */
VTR_LOG_ERROR("Unable to bind physical pb_type '%s' to circuit model '%s'!\n",
target_phy_pb_type_names.back().c_str(),
pb_type_annotation.circuit_model_name().c_str());
return;
}
}
}
/********************************************************************
* This function will link
* - interconnect of pb_type to circuit models in circuit library by following
* the explicit definition in OpenFPGA architecture XML
*
* Note:
* - This function should be executed only AFTER the physical mode and
* physical pb_type annotation is completed
*******************************************************************/
static
void link_vpr_pb_interconnect_to_circuit_model_explicit_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 circuti model for physical pb_type
* we can skip those annotation only for operating pb_type
*/
if (true == pb_type_annotation.is_operating_pb_type()) {
continue;
}
if (0 == pb_type_annotation.interconnect_names().size()) {
continue;
}
VTR_ASSERT(true == pb_type_annotation.is_physical_pb_type());
/* 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_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 = true;
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_phy_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_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;
}
/* Only try to bind interconnect to circuit model when it is defined by users */
for (const std::string& interc_name : pb_type_annotation.interconnect_names()) {
if (false == link_physical_pb_interconnect_to_circuit_model(target_phy_pb_type, interc_name, openfpga_arch.circuit_lib,
pb_type_annotation, vpr_pb_type_annotation)) {
VTR_LOG_ERROR("Unable to bind pb_type '%s' interconnect '%s' to circuit model '%s'!\n",
target_phy_pb_type_names.back().c_str(),
interc_name.c_str(),
pb_type_annotation.circuit_model_name().c_str());
link_success = false;
}
}
}
if (false == link_success) {
/* Not found, error out! */
VTR_LOG_ERROR("Unable to bind interconnects of physical pb_type '%s' to circuit model '%s'!\n",
target_phy_pb_type_names.back().c_str(),
pb_type_annotation.circuit_model_name().c_str());
return;
}
}
}
/********************************************************************
* This function will recursively visit all the pb_type from the top
* pb_type in the graph and infer the circuit model for physical mode
* of pb_types in VPR pb_type graph without OpenFPGA architecture XML
*
* Because only the interconnect in physical modes need circuit model
* annotation, we will skip all the operating modes here
*
* Note:
* - This function will automatically infer the type of circuit model
* that is required and find the default circuit model in the type
* - Interconnect type to Circuit mode type assumption:
* - MUX_INTERC -> CIRCUIT_MODEL_MUX
* - DIRECT_INTERC -> CIRCUIT_MODEL_WIRE
* - COMPLETE_INTERC (single input) -> CIRCUIT_MODEL_WIRE
* - COMPLETE_INTERC (multiple input pins) -> CIRCUIT_MODEL_MUX
*******************************************************************/
static
void rec_infer_vpr_pb_interconnect_circuit_model_annotation(t_pb_type* cur_pb_type,
const CircuitLibrary& circuit_lib,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* We do not check any primitive pb_type */
if (true == is_primitive_pb_type(cur_pb_type)) {
return;
}
/* Get the physical mode from annotation */
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
VTR_ASSERT(nullptr != physical_mode);
/* Annotate the circuit model for each interconnect under this physical mode */
for (t_interconnect* pb_interc : pb_mode_interconnects(physical_mode)) {
/* If the interconnect has been annotated, we skip it */
if (CircuitModelId::INVALID() != vpr_pb_type_annotation.interconnect_circuit_model(pb_interc)) {
continue;
}
/* Infer the circuit model type for a given interconnect */
e_circuit_model_type circuit_model_type = pb_interconnect_require_circuit_model_type(vpr_pb_type_annotation.interconnect_physical_type(pb_interc));
/* Try to find a default circuit model from the circuit library */
CircuitModelId default_circuit_model = circuit_lib.default_model(circuit_model_type);
/* Update the annotation if the model id is valid */
if (CircuitModelId::INVALID() == default_circuit_model) {
VTR_LOG_ERROR("Unable to infer a circuit model for interconnect '%s' under physical mode '%s' of pb_type '%s'!\n",
pb_interc->name,
physical_mode->name,
cur_pb_type->name);
}
vpr_pb_type_annotation.add_interconnect_circuit_model(pb_interc, default_circuit_model);
VTR_LOG("Implicitly infer a circuit model '%s' for interconnect '%s' under physical mode '%s' of pb_type '%s'\n",
circuit_lib.model_name(default_circuit_model).c_str(),
pb_interc->name,
physical_mode->name,
cur_pb_type->name);
}
/* Traverse the pb_type children under the physical mode */
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
rec_infer_vpr_pb_interconnect_circuit_model_annotation(&(physical_mode->pb_type_children[ichild]),
circuit_lib, vpr_pb_type_annotation);
}
}
/********************************************************************
* This function will infer the circuit model for each interconnect
* under a physical mode of a pb_type in VPR pb_type graph without
* OpenFPGA architecture XML
*
* Note:
* This function must be executed AFTER the function
* build_vpr_physical_pb_mode_explicit_annotation()
* build_vpr_physical_pb_mode_implicit_annotation()
*******************************************************************/
static
void link_vpr_pb_interconnect_to_circuit_model_implicit_annotation(const DeviceContext& vpr_device_ctx,
const CircuitLibrary& circuit_lib,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
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;
}
rec_infer_vpr_pb_interconnect_circuit_model_annotation(lb_type.pb_type, circuit_lib, vpr_pb_type_annotation);
}
}
/********************************************************************
* Top-level function to link openfpga architecture to VPR, including:
* - physical pb_type
* - circuit models for pb_type, pb interconnect
*******************************************************************/
void annotate_pb_types(const DeviceContext& vpr_device_ctx,
const Arch& openfpga_arch,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* Annotate physical mode to pb_type in the VPR pb_type graph */
build_vpr_physical_pb_mode_explicit_annotation(vpr_device_ctx, openfpga_arch,
vpr_pb_type_annotation);
build_vpr_physical_pb_mode_implicit_annotation(vpr_device_ctx,
vpr_pb_type_annotation);
check_vpr_physical_pb_mode_annotation(vpr_device_ctx,
const_cast<const VprPbTypeAnnotation&>(vpr_pb_type_annotation));
/* Annotate the physical type for each interconnect under physical modes
* Must run AFTER physical mode annotation is done and
* BEFORE inferring the circuit model for interconnect
*/
annotate_pb_graph_interconnect_physical_type(vpr_device_ctx,
vpr_pb_type_annotation);
/* Annotate physical pb_types to operating pb_type in the VPR pb_type graph */
build_vpr_physical_pb_type_explicit_annotation(vpr_device_ctx, openfpga_arch,
vpr_pb_type_annotation);
build_vpr_physical_pb_type_implicit_annotation(vpr_device_ctx,
vpr_pb_type_annotation);
check_vpr_physical_pb_type_annotation(vpr_device_ctx,
const_cast<const VprPbTypeAnnotation&>(vpr_pb_type_annotation));
/* Link
* - physical pb_type to circuit model
* - interconnect of physical pb_type to circuit model
*/
/* TODO: link the pb_type port to circuit model port here! */
link_vpr_pb_type_to_circuit_model_explicit_annotation(vpr_device_ctx, openfpga_arch,
vpr_pb_type_annotation);
link_vpr_pb_interconnect_to_circuit_model_explicit_annotation(vpr_device_ctx, openfpga_arch,
vpr_pb_type_annotation);
link_vpr_pb_interconnect_to_circuit_model_implicit_annotation(vpr_device_ctx, openfpga_arch.circuit_lib,
vpr_pb_type_annotation);
/* Link physical pb_type to mode_bits */
}
} /* end namespace openfpga */

View File

@ -0,0 +1,24 @@
#ifndef ANNOTATE_PB_TYPES_H
#define ANNOTATE_PB_TYPES_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "openfpga_context.h"
#include "vpr_pb_type_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void annotate_pb_types(const DeviceContext& vpr_device_ctx,
const Arch& openfpga_arch,
VprPbTypeAnnotation& vpr_pb_type_annotation);
} /* end namespace openfpga */
#endif

View File

@ -9,6 +9,8 @@
#include "vpr_pb_type_annotation.h"
#include "pb_type_utils.h"
#include "annotate_pb_types.h"
#include "annotate_pb_graph.h"
#include "openfpga_link_arch.h"
/* Include global variables of VPR */
@ -17,324 +19,25 @@
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* This function will traverse pb_type graph from its top to find
* a pb_type with a given name as well as its hierarchy
*******************************************************************/
static
t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
const std::vector<std::string>& target_pb_type_names,
const std::vector<std::string>& target_pb_mode_names) {
/* Ensure that number of parent names and modes matches */
VTR_ASSERT_SAFE(target_pb_type_names.size() == target_pb_mode_names.size() + 1);
t_pb_type* cur_pb_type = top_pb_type;
/* If the top pb_type is what we want, we can return here */
if (1 == target_pb_type_names.size()) {
if (target_pb_type_names[0] == std::string(top_pb_type->name)) {
return top_pb_type;
}
/* Not match, return null pointer */
return nullptr;
}
/* We start from the first element of the parent names and parent modes.
* If the pb_type does not match in name, we fail
* If we cannot find a mode match the name, we fail
*/
for (size_t i = 0; i < target_pb_type_names.size() - 1; ++i) {
/* If this level does not match, search fail */
if (target_pb_type_names[i] != std::string(cur_pb_type->name)) {
return nullptr;
}
/* Find if the mode matches */
t_mode* cur_mode = find_pb_type_mode(cur_pb_type, target_pb_mode_names[i].c_str());
if (nullptr == cur_mode) {
return nullptr;
}
/* Go to the next level of pb_type */
cur_pb_type = find_mode_child_pb_type(cur_mode, target_pb_type_names[i + 1].c_str());
if (nullptr == cur_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) {
return cur_pb_type;
}
}
/* Reach here, it means we find nothing */
return nullptr;
}
/********************************************************************
* This function will identify the physical pb_type for each multi-mode
* pb_type in VPR pb_type graph by following the explicit definition
* in OpenFPGA architecture XML
*******************************************************************/
static
void build_vpr_physical_pb_mode_explicit_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 physical mode name,
* we can skip those has not physical mode defined
*/
if (true == pb_type_annotation.physical_mode_name().empty()) {
continue;
}
/* Identify if the pb_type is operating or physical,
* For operating pb_type, get the full name of operating pb_type
* For physical pb_type, get the full name of physical pb_type
*/
std::vector<std::string> target_pb_type_names;
std::vector<std::string> target_pb_mode_names;
if (true == pb_type_annotation.is_operating_pb_type()) {
target_pb_type_names = pb_type_annotation.operating_parent_pb_type_names();
target_pb_type_names.push_back(pb_type_annotation.operating_pb_type_name());
target_pb_mode_names = pb_type_annotation.operating_parent_mode_names();
}
if (true == pb_type_annotation.is_physical_pb_type()) {
target_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
target_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
target_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_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_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 pb_type in the graph */
t_pb_type* target_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_pb_type_names,
target_pb_mode_names);
if (nullptr == target_pb_type) {
continue;
}
/* Found, we update the annotation by assigning the physical mode */
t_mode* physical_mode = find_pb_type_mode(target_pb_type, pb_type_annotation.physical_mode_name().c_str());
vpr_pb_type_annotation.add_pb_type_physical_mode(target_pb_type, physical_mode);
/* Give a message */
VTR_LOG("Annotate pb_type '%s' with physical mode '%s'\n",
target_pb_type->name, physical_mode->name);
link_success = true;
break;
}
if (false == link_success) {
/* Not found, error out! */
VTR_LOG_ERROR("Unable to find the pb_type '%s' in VPR architecture definition!\n",
target_pb_type_names.back().c_str());
return;
}
}
}
/********************************************************************
* 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
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
*
* The following rule is applied:
* if there is only 1 mode under a pb_type, it will be the default
* physical mode for this pb_type
*******************************************************************/
static
void rec_infer_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
/* We do not check any primitive pb_type */
if (true == is_primitive_pb_type(cur_pb_type)) {
return;
}
/* For non-primitive pb_type:
* - if there is only one mode, it will be the physical mode
* we just need to make sure that we do not repeatedly annotate this
* - if there are multiple modes, we should be able to find a physical mode
* and then go recursively
*/
t_mode* physical_mode = nullptr;
if (1 == cur_pb_type->num_modes) {
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
/* Not assigned by explicit annotation, we should infer here */
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
VTR_LOG("Implicitly infer physical mode '%s' for pb_type '%s'\n",
cur_pb_type->modes[0].name, cur_pb_type->name);
}
} else {
VTR_ASSERT(1 < cur_pb_type->num_modes);
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
/* Not assigned by explicit annotation, we should infer here */
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
cur_pb_type->name);
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
return;
}
}
/* Get the physical mode from annotation */
physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
VTR_ASSERT(nullptr != physical_mode);
/* Traverse the pb_type children under the physical mode */
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
rec_infer_vpr_physical_pb_mode_annotation(&(physical_mode->pb_type_children[ichild]),
vpr_pb_type_annotation);
}
}
/********************************************************************
* This function will infer the physical pb_type for each multi-mode
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
*
* The following rule is applied:
* if there is only 1 mode under a pb_type, it will be the default
* physical mode for this pb_type
*
* Note:
* This function must be executed AFTER the function
* build_vpr_physical_pb_mode_explicit_annotation()
*******************************************************************/
static
void build_vpr_physical_pb_mode_implicit_annotation(const DeviceContext& vpr_device_ctx,
VprPbTypeAnnotation& vpr_pb_type_annotation) {
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;
}
rec_infer_vpr_physical_pb_mode_annotation(lb_type.pb_type, vpr_pb_type_annotation);
}
}
/********************************************************************
* This function will recursively traverse pb_type graph to ensure
* 1. there is only a physical mode under each pb_type
* 2. physical mode appears only when its parent is a physical mode.
*******************************************************************/
static
void rec_check_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
const bool& expect_physical_mode,
const VprPbTypeAnnotation& vpr_pb_type_annotation,
size_t& num_err) {
/* We do not check any primitive pb_type */
if (true == is_primitive_pb_type(cur_pb_type)) {
return;
}
/* For non-primitive pb_type:
* - If we expect a physical mode to exist under this pb_type
* we should be able to find one in the annoation
* - If we do NOT expect a physical mode, make sure we find
* nothing in the annotation
*/
if (true == expect_physical_mode) {
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
cur_pb_type->name);
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
num_err++;
return;
}
} else {
VTR_ASSERT_SAFE(false == expect_physical_mode);
if (nullptr != vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
VTR_LOG_ERROR("Find a physical mode '%s' for pb_type '%s' which is not under any physical mode!\n",
vpr_pb_type_annotation.physical_mode(cur_pb_type)->name,
cur_pb_type->name);
num_err++;
return;
}
}
/* Traverse all the modes
* - for pb_type children under a physical mode, we expect an physical mode
* - for pb_type children under non-physical mode, we expect no physical mode
*/
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
bool expect_child_physical_mode = false;
if (&(cur_pb_type->modes[imode]) == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
expect_child_physical_mode = true && expect_physical_mode;
}
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
rec_check_vpr_physical_pb_mode_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
expect_child_physical_mode, vpr_pb_type_annotation,
num_err);
}
}
}
/********************************************************************
* This function will check the physical mode annotation for
* each pb_type in the device
*******************************************************************/
static
void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
size_t num_err = 0;
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;
}
/* Top pb_type should always has a physical mode! */
rec_check_vpr_physical_pb_mode_annotation(lb_type.pb_type, true, vpr_pb_type_annotation, num_err);
}
if (0 == num_err) {
VTR_LOG("Check physical mode annotation for pb_types passed.\n");
} else {
VTR_LOG("Check physical mode annotation for pb_types failed with %ld errors!\n",
num_err);
}
}
/********************************************************************
* Top-level function to link openfpga architecture to VPR, including:
* - physical pb_type
* - idle pb_type
* - circuit models for pb_type, pb interconnect and routing architecture
* - mode selection bits for pb_type and pb interconnect
* - circuit models for pb_type and pb interconnect
* - physical pb_graph nodes and pb_graph pins
* - circuit models for global routing architecture
*******************************************************************/
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 */
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(),
openfpga_context.mutable_vpr_pb_type_annotation());
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 */
/* Link physical pb_type to circuit model */
/* Annotate pb_type graphs
* - physical pb_type
* - mode selection bits for pb_type and pb interconnect
* - circuit models for pb_type and pb interconnect
*/
annotate_pb_types(g_vpr_ctx.device(), openfpga_context.arch(),
openfpga_context.mutable_vpr_pb_type_annotation());
/* Link routing architecture to circuit model */
}

View File

@ -1,5 +1,5 @@
#ifndef OPENFPGA_LINK_ARCH_COMMAND_H
#define OPENFPGA_LINK_ARCH_COMMAND_H
#ifndef OPENFPGA_LINK_ARCH_H
#define OPENFPGA_LINK_ARCH_H
/********************************************************************
* Include header files that are required by function declaration

View File

@ -0,0 +1,41 @@
/********************************************************************
* This file includes most utilized functions for the pb_graph_node
* and pb_graph_pin data structure in the OpenFPGA context
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "pb_graph_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* This function aims to find out all the pb_graph_pins that drive
* a given pb_graph pin w.r.t. a given interconnect definition
*******************************************************************/
std::vector<t_pb_graph_pin*> pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin,
t_interconnect* selected_interconnect) {
std::vector<t_pb_graph_pin*> inputs;
/* Search the input edges only, stats on the size of MUX we may need (fan-in) */
for (int iedge = 0; iedge < pb_graph_pin->num_input_edges; ++iedge) {
/* We care the only edges in the selected mode */
if (selected_interconnect != pb_graph_pin->input_edges[iedge]->interconnect) {
continue;
}
for (int ipin = 0; ipin < pb_graph_pin->input_edges[iedge]->num_input_pins; ++ipin) {
/* Ensure that the pin is unique in the list */
if (inputs.end() != std::find(inputs.begin(), inputs.end(), pb_graph_pin->input_edges[iedge]->input_pins[ipin])) {
continue;
}
/* Unique pin, push to the vector */
inputs.push_back(pb_graph_pin->input_edges[iedge]->input_pins[ipin]);
}
}
return inputs;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef PB_GRAPH_UTILS_H
#define PB_GRAPH_UTILS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include <vector>
#include "physical_types.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
std::vector<t_pb_graph_pin*> pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin,
t_interconnect* selected_interconnect);
} /* end namespace openfpga */
#endif

View File

@ -1,7 +1,9 @@
/********************************************************************
* This file includes most utilized functions for the pb_type
* and pb_graph_node data structure in the OpenFPGA context
* This file includes most utilized functions for the t_pb_type,
* t_mode and t_port data structure in the OpenFPGA context
*******************************************************************/
#include <map>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
@ -64,4 +66,166 @@ 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;
}
/********************************************************************
* This function will traverse pb_type graph from its top to find
* a pb_type with a given name as well as its hierarchy
*******************************************************************/
t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
const std::vector<std::string>& target_pb_type_names,
const std::vector<std::string>& target_pb_mode_names) {
/* Ensure that number of parent names and modes matches */
VTR_ASSERT_SAFE(target_pb_type_names.size() == target_pb_mode_names.size() + 1);
t_pb_type* cur_pb_type = top_pb_type;
/* If the top pb_type is what we want, we can return here */
if (1 == target_pb_type_names.size()) {
if (target_pb_type_names[0] == std::string(top_pb_type->name)) {
return top_pb_type;
}
/* Not match, return null pointer */
return nullptr;
}
/* We start from the first element of the parent names and parent modes.
* If the pb_type does not match in name, we fail
* If we cannot find a mode match the name, we fail
*/
for (size_t i = 0; i < target_pb_type_names.size() - 1; ++i) {
/* If this level does not match, search fail */
if (target_pb_type_names[i] != std::string(cur_pb_type->name)) {
return nullptr;
}
/* Find if the mode matches */
t_mode* cur_mode = find_pb_type_mode(cur_pb_type, target_pb_mode_names[i].c_str());
if (nullptr == cur_mode) {
return nullptr;
}
/* Go to the next level of pb_type */
cur_pb_type = find_mode_child_pb_type(cur_mode, target_pb_type_names[i + 1].c_str());
if (nullptr == cur_pb_type) {
return nullptr;
}
/* If this is already the last pb_type in the list, this is what we want */
if (i + 1 == target_pb_type_names.size() - 1) {
return cur_pb_type;
}
}
/* Reach here, it means we find nothing */
return nullptr;
}
/********************************************************************
* This function will return all the interconnects defined under a mode
* of pb_type
*******************************************************************/
std::vector<t_interconnect*> pb_mode_interconnects(t_mode* pb_mode) {
std::vector<t_interconnect*> interc;
for (int i = 0; i < pb_mode->num_interconnect; ++i) {
interc.push_back(&(pb_mode->interconnect[i]));
}
return interc;
}
/********************************************************************
* This function will try to find an interconnect defined under a mode
* of pb_type with a given name.
* If not found, return null pointer
*******************************************************************/
t_interconnect* find_pb_mode_interconnect(t_mode* pb_mode, const char* interc_name) {
for (int i = 0; i < pb_mode->num_interconnect; ++i) {
if (std::string(interc_name) == std::string(pb_mode->interconnect[i].name)) {
return &(pb_mode->interconnect[i]);
}
}
/* Reach here, it means we find nothing */
return nullptr;
}
/********************************************************************
* This function will automatically infer the actual type of an interconnect
* that will be used to implement the physical design:
* - MUX_INTERC -> MUX_INTERC
* - DIRECT_INTERC -> DIRECT_INTERC
* - COMPLETE_INTERC (single input) -> DIRECT_INTERC
* - COMPLETE_INTERC (multiple input pins) -> MUX_INTERC
*******************************************************************/
e_interconnect pb_interconnect_physical_type(t_interconnect* pb_interc,
const size_t& num_inputs) {
/* Check */
VTR_ASSERT(nullptr != pb_interc);
/* Initialize the interconnection type that will be implemented in SPICE netlist*/
switch (pb_interc->type) {
case DIRECT_INTERC:
return DIRECT_INTERC;
break;
case COMPLETE_INTERC:
if (1 == num_inputs) {
return DIRECT_INTERC;
} else {
VTR_ASSERT(1 < num_inputs);
return MUX_INTERC;
}
break;
case MUX_INTERC:
return MUX_INTERC;
break;
default:
VTR_LOG_ERROR("Invalid type for interconnection '%s'!\n",
pb_interc->name);
exit(1);
}
return NUM_INTERC_TYPES;
}
/********************************************************************
* This function will automatically infer the actual type of an interconnect
* that will be used to implement the physical design:
* - MUX_INTERC -> CIRCUIT_MODEL_MUX
* - DIRECT_INTERC -> CIRCUIT_MODEL_WIRE
*
* Note:
* - COMPLETE_INTERC should not appear here!
* - We assume the interconnect type is the physical type
* after interconnect physical type annotation is done!
*******************************************************************/
e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_interconnect& pb_interc_type) {
/* A map from interconnect type to circuit model type */
std::map<e_interconnect, e_circuit_model_type> type_mapping;
type_mapping[MUX_INTERC] = CIRCUIT_MODEL_MUX;
type_mapping[DIRECT_INTERC] = CIRCUIT_MODEL_WIRE;
VTR_ASSERT((MUX_INTERC == pb_interc_type) || (DIRECT_INTERC == pb_interc_type));
return type_mapping.at(pb_interc_type);
}
} /* end namespace openfpga */

View File

@ -4,7 +4,10 @@
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include <vector>
#include "physical_types.h"
#include "circuit_library.h"
/********************************************************************
* Function declaration
@ -21,6 +24,23 @@ 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);
t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
const std::vector<std::string>& target_pb_type_names,
const std::vector<std::string>& target_pb_mode_names);
std::vector<t_interconnect*> pb_mode_interconnects(t_mode* pb_mode);
t_interconnect* find_pb_mode_interconnect(t_mode* pb_mode, const char* interc_name);
e_interconnect pb_interconnect_physical_type(t_interconnect* pb_interc,
const size_t& num_inputs);
e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_interconnect& pb_interc_type);
} /* end namespace openfpga */
#endif

View File

@ -16,8 +16,18 @@ VprPbTypeAnnotation::VprPbTypeAnnotation() {
}
/************************************************************************
* Public mutators
* Public accessors
***********************************************************************/
bool VprPbTypeAnnotation::is_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 false;
}
/* A physical pb_type should be mapped to itself! Otherwise, it is an operating pb_type */
return pb_type == physical_pb_types_.at(pb_type);
}
t_mode* VprPbTypeAnnotation::physical_mode(t_pb_type* pb_type) const {
/* Ensure that the pb_type is in the list */
std::map<t_pb_type*, t_mode*>::const_iterator it = physical_pb_modes_.find(pb_type);
@ -27,6 +37,64 @@ 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);
}
CircuitModelId VprPbTypeAnnotation::pb_type_circuit_model(t_pb_type* physical_pb_type) const {
/* Ensure that the pb_type is in the list */
std::map<t_pb_type*, CircuitModelId>::const_iterator it = pb_type_circuit_models_.find(physical_pb_type);
if (it == pb_type_circuit_models_.end()) {
/* Return an invalid circuit model id */
return CircuitModelId::INVALID();
}
return pb_type_circuit_models_.at(physical_pb_type);
}
CircuitModelId VprPbTypeAnnotation::interconnect_circuit_model(t_interconnect* pb_interconnect) const {
/* Ensure that the pb_type is in the list */
std::map<t_interconnect*, CircuitModelId>::const_iterator it = interconnect_circuit_models_.find(pb_interconnect);
if (it == interconnect_circuit_models_.end()) {
/* Return an invalid circuit model id */
return CircuitModelId::INVALID();
}
return interconnect_circuit_models_.at(pb_interconnect);
}
e_interconnect VprPbTypeAnnotation::interconnect_physical_type(t_interconnect* pb_interconnect) const {
/* Ensure that the pb_type is in the list */
std::map<t_interconnect*, e_interconnect>::const_iterator it = interconnect_physical_types_.find(pb_interconnect);
if (it == interconnect_physical_types_.end()) {
/* Return an invalid circuit model id */
return NUM_INTERC_TYPES;
}
return interconnect_physical_types_.at(pb_interconnect);
}
/************************************************************************
* Public mutators
***********************************************************************/
@ -41,4 +109,74 @@ 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;
}
void VprPbTypeAnnotation::add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model) {
/* Warn any override attempt */
std::map<t_pb_type*, CircuitModelId>::const_iterator it = pb_type_circuit_models_.find(physical_pb_type);
if (it != pb_type_circuit_models_.end()) {
VTR_LOG_WARN("Override the circuit model for physical pb_type '%s'!\n",
physical_pb_type->name);
}
pb_type_circuit_models_[physical_pb_type] = circuit_model;
}
void VprPbTypeAnnotation::add_interconnect_circuit_model(t_interconnect* pb_interconnect, const CircuitModelId& circuit_model) {
/* Warn any override attempt */
std::map<t_interconnect*, CircuitModelId>::const_iterator it = interconnect_circuit_models_.find(pb_interconnect);
if (it != interconnect_circuit_models_.end()) {
VTR_LOG_WARN("Override the circuit model for interconnect '%s'!\n",
pb_interconnect->name);
}
interconnect_circuit_models_[pb_interconnect] = circuit_model;
}
void VprPbTypeAnnotation::add_interconnect_physical_type(t_interconnect* pb_interconnect,
const e_interconnect& physical_type) {
/* Warn any override attempt */
std::map<t_interconnect*, e_interconnect>::const_iterator it = interconnect_physical_types_.find(pb_interconnect);
if (it != interconnect_physical_types_.end()) {
VTR_LOG_WARN("Override the physical interconnect for interconnect '%s'!\n",
pb_interconnect->name);
}
interconnect_physical_types_[pb_interconnect] = physical_type;
}
} /* 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 */
@ -28,14 +29,76 @@ class VprPbTypeAnnotation {
public: /* Constructor */
VprPbTypeAnnotation();
public: /* Public accessors */
bool is_physical_pb_type(t_pb_type* pb_type) const;
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;
CircuitModelId pb_type_circuit_model(t_pb_type* physical_pb_type) const;
CircuitModelId interconnect_circuit_model(t_interconnect* pb_interconnect) const;
e_interconnect interconnect_physical_type(t_interconnect* pb_interconnect) 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);
void add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model);
void add_interconnect_circuit_model(t_interconnect* pb_interconnect, const CircuitModelId& circuit_model);
void add_interconnect_physical_type(t_interconnect* pb_interconnect, const e_interconnect& physical_type);
private: /* Internal data */
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 interconnect of a physical pb_type to its circuit model
* Note:
* - the pb_type MUST be a physical pb_type itself
*/
std::map<t_interconnect*, CircuitModelId> interconnect_circuit_models_;
/* Physical type of interconnect
* Note:
* - only applicable to an interconnect belongs to physical mode
*/
std::map<t_interconnect*, e_interconnect> interconnect_physical_types_;
/* 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*/

View File

@ -134,16 +134,16 @@
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0" />
</circuit_model>
<circuit_model type="lut" name="lut5" prefix="lut5" dump_structural_verilog="true">
<circuit_model type="lut" name="lut6" prefix="lut6" dump_structural_verilog="true">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="5"/>
<port type="input" prefix="in" size="6"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="32"/>
<port type="sram" prefix="sram" size="64"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="ccff" name="sc_dff_compact" prefix="scff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/ff.v">

View File

@ -6,3 +6,6 @@ read_openfpga_arch -f ./test_openfpga_arch/k6_N10_40nm_openfpga.xml
# Annotate the OpenFPGA architecture to VPR data base
link_openfpga_arch
# Finish and exit OpenFPGA
exit