From caeb0bfff89a4b1c09f4dd89be7699618f77aa31 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Jan 2020 14:27:35 -0700 Subject: [PATCH] add physical pb_type binding for explicit annotations --- openfpga/src/base/openfpga_link_arch.cpp | 167 ++++++++++++++++++- openfpga/src/base/pb_type_utils.cpp | 24 +++ openfpga/src/base/pb_type_utils.h | 5 + openfpga/src/base/vpr_pb_type_annotation.cpp | 64 +++++++ openfpga/src/base/vpr_pb_type_annotation.h | 47 ++++++ 5 files changed, 301 insertions(+), 6 deletions(-) diff --git a/openfpga/src/base/openfpga_link_arch.cpp b/openfpga/src/base/openfpga_link_arch.cpp index d01841074..443373d20 100644 --- a/openfpga/src/base/openfpga_link_arch.cpp +++ b/openfpga/src/base/openfpga_link_arch.cpp @@ -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 target_op_pb_type_names; + std::vector 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 target_phy_pb_type_names; + std::vector 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 */ diff --git a/openfpga/src/base/pb_type_utils.cpp b/openfpga/src/base/pb_type_utils.cpp index 7a69ad37c..1d0c31b6c 100644 --- a/openfpga/src/base/pb_type_utils.cpp +++ b/openfpga/src/base/pb_type_utils.cpp @@ -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 pb_type_ports(t_pb_type* pb_type) { + std::vector 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 */ diff --git a/openfpga/src/base/pb_type_utils.h b/openfpga/src/base/pb_type_utils.h index c0c1881d5..902f203e3 100644 --- a/openfpga/src/base/pb_type_utils.h +++ b/openfpga/src/base/pb_type_utils.h @@ -4,6 +4,7 @@ /******************************************************************** * Include header files that are required by function declaration *******************************************************************/ +#include #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 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 diff --git a/openfpga/src/base/vpr_pb_type_annotation.cpp b/openfpga/src/base/vpr_pb_type_annotation.cpp index 1d4beb1ff..e89045307 100644 --- a/openfpga/src/base/vpr_pb_type_annotation.cpp +++ b/openfpga/src/base/vpr_pb_type_annotation.cpp @@ -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::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::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::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::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::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::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*/ diff --git a/openfpga/src/base/vpr_pb_type_annotation.h b/openfpga/src/base/vpr_pb_type_annotation.h index 5410a7ca9..90b29598f 100644 --- a/openfpga/src/base/vpr_pb_type_annotation.h +++ b/openfpga/src/base/vpr_pb_type_annotation.h @@ -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 is_physical_pb_types_; + + /* Pair a regular pb_type to its physical pb_type */ std::map 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 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 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> 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 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 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 physical_pb_graph_nodes_; }; } /* End namespace openfpga*/