diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 36901e6f0..503427303 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -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. */ diff --git a/openfpga/src/base/annotate_pb_graph.cpp b/openfpga/src/base/annotate_pb_graph.cpp new file mode 100644 index 000000000..82e214067 --- /dev/null +++ b/openfpga/src/base/annotate_pb_graph.cpp @@ -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 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 */ + diff --git a/openfpga/src/base/annotate_pb_graph.h b/openfpga/src/base/annotate_pb_graph.h new file mode 100644 index 000000000..8749cd28f --- /dev/null +++ b/openfpga/src/base/annotate_pb_graph.h @@ -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 diff --git a/openfpga/src/base/annotate_pb_types.cpp b/openfpga/src/base/annotate_pb_types.cpp new file mode 100644 index 000000000..c4605325c --- /dev/null +++ b/openfpga/src/base/annotate_pb_types.cpp @@ -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 target_pb_type_names; + std::vector 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 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; + } + } +} + +/******************************************************************** + * 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 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_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 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_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(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(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 */ diff --git a/openfpga/src/base/annotate_pb_types.h b/openfpga/src/base/annotate_pb_types.h new file mode 100644 index 000000000..494b2c771 --- /dev/null +++ b/openfpga/src/base/annotate_pb_types.h @@ -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 diff --git a/openfpga/src/base/openfpga_link_arch.cpp b/openfpga/src/base/openfpga_link_arch.cpp index d01841074..a30453d1c 100644 --- a/openfpga/src/base/openfpga_link_arch.cpp +++ b/openfpga/src/base/openfpga_link_arch.cpp @@ -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& target_pb_type_names, - const std::vector& 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 target_pb_type_names; - std::vector 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 */ } diff --git a/openfpga/src/base/openfpga_link_arch.h b/openfpga/src/base/openfpga_link_arch.h index c36c57711..3775ee789 100644 --- a/openfpga/src/base/openfpga_link_arch.h +++ b/openfpga/src/base/openfpga_link_arch.h @@ -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 diff --git a/openfpga/src/base/pb_graph_utils.cpp b/openfpga/src/base/pb_graph_utils.cpp new file mode 100644 index 000000000..84e642bde --- /dev/null +++ b/openfpga/src/base/pb_graph_utils.cpp @@ -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 pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin, + t_interconnect* selected_interconnect) { + std::vector 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 */ diff --git a/openfpga/src/base/pb_graph_utils.h b/openfpga/src/base/pb_graph_utils.h new file mode 100644 index 000000000..d46457b7d --- /dev/null +++ b/openfpga/src/base/pb_graph_utils.h @@ -0,0 +1,23 @@ +#ifndef PB_GRAPH_UTILS_H +#define PB_GRAPH_UTILS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include +#include "physical_types.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +std::vector pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin, + t_interconnect* selected_interconnect); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/base/pb_type_utils.cpp b/openfpga/src/base/pb_type_utils.cpp index 7a69ad37c..090661b50 100644 --- a/openfpga/src/base/pb_type_utils.cpp +++ b/openfpga/src/base/pb_type_utils.cpp @@ -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 + /* 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 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; +} + +/******************************************************************** + * 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& target_pb_type_names, + const std::vector& 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 pb_mode_interconnects(t_mode* pb_mode) { + std::vector 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 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 */ diff --git a/openfpga/src/base/pb_type_utils.h b/openfpga/src/base/pb_type_utils.h index c0c1881d5..ac3ade343 100644 --- a/openfpga/src/base/pb_type_utils.h +++ b/openfpga/src/base/pb_type_utils.h @@ -4,7 +4,10 @@ /******************************************************************** * Include header files that are required by function declaration *******************************************************************/ +#include +#include #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 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& target_pb_type_names, + const std::vector& target_pb_mode_names); + +std::vector 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 diff --git a/openfpga/src/base/vpr_pb_type_annotation.cpp b/openfpga/src/base/vpr_pb_type_annotation.cpp index 1d4beb1ff..97dc7354b 100644 --- a/openfpga/src/base/vpr_pb_type_annotation.cpp +++ b/openfpga/src/base/vpr_pb_type_annotation.cpp @@ -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::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::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::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); +} + +CircuitModelId VprPbTypeAnnotation::pb_type_circuit_model(t_pb_type* physical_pb_type) const { + /* Ensure that the pb_type is in the list */ + std::map::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::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::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::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; +} + +void VprPbTypeAnnotation::add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model) { + /* Warn any override attempt */ + std::map::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::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::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*/ diff --git a/openfpga/src/base/vpr_pb_type_annotation.h b/openfpga/src/base/vpr_pb_type_annotation.h index 5410a7ca9..824a81e87 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 */ @@ -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 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 interconnect of a physical pb_type to its circuit model + * Note: + * - the pb_type MUST be a physical pb_type itself + */ + std::map interconnect_circuit_models_; + + /* Physical type of interconnect + * Note: + * - only applicable to an interconnect belongs to physical mode + */ + std::map 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> 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*/ diff --git a/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml b/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml index 23607e234..d93495f6b 100644 --- a/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml +++ b/openfpga/test_openfpga_arch/k6_N10_40nm_openfpga.xml @@ -134,16 +134,16 @@ - + - + - + diff --git a/openfpga/test_script/s298.openfpga b/openfpga/test_script/s298.openfpga index ad12f4807..6d4eaa434 100644 --- a/openfpga/test_script/s298.openfpga +++ b/openfpga/test_script/s298.openfpga @@ -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