Merge branch 'refactoring' into dev
This commit is contained in:
commit
bfaa2442a2
|
@ -162,7 +162,8 @@ enum e_pin_type {
|
||||||
enum e_interconnect {
|
enum e_interconnect {
|
||||||
COMPLETE_INTERC = 1,
|
COMPLETE_INTERC = 1,
|
||||||
DIRECT_INTERC = 2,
|
DIRECT_INTERC = 2,
|
||||||
MUX_INTERC = 3
|
MUX_INTERC = 3,
|
||||||
|
NUM_INTERC_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Orientations. */
|
/* Orientations. */
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions that are used to annotate pb_graph_node
|
||||||
|
* and pb_graph_pins from VPR to OpenFPGA
|
||||||
|
*******************************************************************/
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
|
||||||
|
#include "pb_type_utils.h"
|
||||||
|
#include "pb_graph_utils.h"
|
||||||
|
|
||||||
|
#include "annotate_pb_graph.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will recursively walk through all the pb_graph nodes
|
||||||
|
* starting from a top node.
|
||||||
|
* It aims to annotate the physical type of each interconnect.
|
||||||
|
* This is due to that the type of interconnect 'complete' may diverge
|
||||||
|
* in physical implmentation.
|
||||||
|
* - When there is only one input driving a 'complete' interconnection,
|
||||||
|
* it will be implemented with wires
|
||||||
|
* - When there are multiple inputs driving a 'complete' interconnection,
|
||||||
|
* it will be implemented with routing multiplexers
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void rec_build_vpr_pb_graph_interconnect_physical_type_annotation(t_pb_graph_node* pb_graph_node,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Skip the root node because we start from the inputs of child pb_graph node
|
||||||
|
*
|
||||||
|
* pb_graph_node
|
||||||
|
* +----------------------------------
|
||||||
|
* | child_pb_graph_node
|
||||||
|
* | +-----------------
|
||||||
|
* | |
|
||||||
|
* |-------------+-->input_pins
|
||||||
|
* | |
|
||||||
|
* |-------------+-->clock_pins
|
||||||
|
* |
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (false == pb_graph_node->is_root()) {
|
||||||
|
/* We only care the physical modes! But we have to find it through the parent node */
|
||||||
|
t_mode* child_physical_mode = vpr_pb_type_annotation.physical_mode(pb_graph_node->parent_pb_graph_node->pb_type);
|
||||||
|
VTR_ASSERT(nullptr != child_physical_mode);
|
||||||
|
|
||||||
|
std::map<t_interconnect*, size_t> interc_num_inputs;
|
||||||
|
/* Initialize the counter */
|
||||||
|
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
|
||||||
|
interc_num_inputs[interc] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only care input and clock pins */
|
||||||
|
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
|
||||||
|
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||||
|
/* For each interconnect, we count the total number of inputs */
|
||||||
|
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
|
||||||
|
interc_num_inputs[interc] += pb_graph_pin_inputs(&(pb_graph_node->input_pins[iport][ipin]), interc).size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int iport = 0; iport < pb_graph_node->num_clock_ports; ++iport) {
|
||||||
|
for (int ipin = 0; ipin < pb_graph_node->num_clock_pins[iport]; ++ipin) {
|
||||||
|
/* For each interconnect, we count the total number of inputs */
|
||||||
|
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
|
||||||
|
interc_num_inputs[interc] += pb_graph_pin_inputs(&(pb_graph_node->clock_pins[iport][ipin]), interc).size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For each interconnect that has more than 1 input, we can infer the physical type */
|
||||||
|
for (t_interconnect* interc : pb_mode_interconnects(child_physical_mode)) {
|
||||||
|
e_interconnect interc_physical_type = pb_interconnect_physical_type(interc, interc_num_inputs[interc]);
|
||||||
|
if (interc_physical_type == vpr_pb_type_annotation.interconnect_physical_type(interc)) {
|
||||||
|
/* Skip annotation if we have already done! */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vpr_pb_type_annotation.add_interconnect_physical_type(interc, interc_physical_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we reach a primitive pb_graph node, we return */
|
||||||
|
if (true == is_primitive_pb_type(pb_graph_node->pb_type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recursively visit all the child pb_graph_nodes */
|
||||||
|
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(pb_graph_node->pb_type);
|
||||||
|
VTR_ASSERT(nullptr != physical_mode);
|
||||||
|
for (int ipb = 0; ipb < physical_mode->num_pb_type_children; ++ipb) {
|
||||||
|
/* Each child may exist multiple times in the hierarchy*/
|
||||||
|
for (int jpb = 0; jpb < physical_mode->pb_type_children[ipb].num_pb; ++jpb) {
|
||||||
|
rec_build_vpr_pb_graph_interconnect_physical_type_annotation(&(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb][jpb]), vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function aims to annotate the physical type for each interconnect
|
||||||
|
* inside the pb_graph
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - This function should be executed AFTER functions
|
||||||
|
* build_vpr_physical_pb_mode_explicit_annotation()
|
||||||
|
* build_vpr_physical_pb_mode_implicit_annotation()
|
||||||
|
*******************************************************************/
|
||||||
|
void annotate_pb_graph_interconnect_physical_type(const DeviceContext& vpr_device_ctx,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_graph head */
|
||||||
|
if (nullptr == lb_type.pb_graph_head) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rec_build_vpr_pb_graph_interconnect_physical_type_annotation(lb_type.pb_graph_head, vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,985 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions to build links between pb_types
|
||||||
|
* in particular to annotate the physical mode and physical pb_type
|
||||||
|
*******************************************************************/
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_time.h"
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
|
||||||
|
#include "vpr_pb_type_annotation.h"
|
||||||
|
#include "pb_type_utils.h"
|
||||||
|
#include "annotate_pb_graph.h"
|
||||||
|
#include "annotate_pb_types.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will identify the physical mode for each multi-mode
|
||||||
|
* pb_type in VPR pb_type graph by following the explicit definition
|
||||||
|
* in OpenFPGA architecture XML
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void build_vpr_physical_pb_mode_explicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
const Arch& openfpga_arch,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Walk through the pb_type annotation stored in the openfpga arch */
|
||||||
|
for (const PbTypeAnnotation& pb_type_annotation : openfpga_arch.pb_type_annotations) {
|
||||||
|
/* Since our target is to annotate the physical mode name,
|
||||||
|
* we can skip those has not physical mode defined
|
||||||
|
*/
|
||||||
|
if (true == pb_type_annotation.physical_mode_name().empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Identify if the pb_type is operating or physical,
|
||||||
|
* For operating pb_type, get the full name of operating pb_type
|
||||||
|
* For physical pb_type, get the full name of physical pb_type
|
||||||
|
*/
|
||||||
|
std::vector<std::string> target_pb_type_names;
|
||||||
|
std::vector<std::string> target_pb_mode_names;
|
||||||
|
|
||||||
|
if (true == pb_type_annotation.is_operating_pb_type()) {
|
||||||
|
target_pb_type_names = pb_type_annotation.operating_parent_pb_type_names();
|
||||||
|
target_pb_type_names.push_back(pb_type_annotation.operating_pb_type_name());
|
||||||
|
target_pb_mode_names = pb_type_annotation.operating_parent_mode_names();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true == pb_type_annotation.is_physical_pb_type()) {
|
||||||
|
target_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
|
||||||
|
target_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
|
||||||
|
target_pb_mode_names = pb_type_annotation.physical_parent_mode_names();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We must have at least one pb_type in the list */
|
||||||
|
VTR_ASSERT_SAFE(0 < target_pb_type_names.size());
|
||||||
|
|
||||||
|
/* Pb type information are located at the logic_block_types in the device context of VPR
|
||||||
|
* We iterate over the vectors and find the pb_type matches the parent_pb_type_name
|
||||||
|
*/
|
||||||
|
bool link_success = false;
|
||||||
|
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Check the name of the top-level pb_type, if it does not match, we can bypass */
|
||||||
|
if (target_pb_type_names[0] != std::string(lb_type.pb_type->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Match the name in the top-level, we go further to search the pb_type in the graph */
|
||||||
|
t_pb_type* target_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_pb_type_names,
|
||||||
|
target_pb_mode_names);
|
||||||
|
if (nullptr == target_pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Found, we update the annotation by assigning the physical mode */
|
||||||
|
t_mode* physical_mode = find_pb_type_mode(target_pb_type, pb_type_annotation.physical_mode_name().c_str());
|
||||||
|
vpr_pb_type_annotation.add_pb_type_physical_mode(target_pb_type, physical_mode);
|
||||||
|
|
||||||
|
/* Give a message */
|
||||||
|
VTR_LOG("Annotate pb_type '%s' with physical mode '%s'\n",
|
||||||
|
target_pb_type->name, physical_mode->name);
|
||||||
|
|
||||||
|
link_success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false == link_success) {
|
||||||
|
/* Not found, error out! */
|
||||||
|
VTR_LOG_ERROR("Unable to find the pb_type '%s' in VPR architecture definition!\n",
|
||||||
|
target_pb_type_names.back().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will recursively visit all the pb_type from the top
|
||||||
|
* pb_type in the graph and
|
||||||
|
* infer the physical mode for each multi-mode
|
||||||
|
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* The following rule is applied:
|
||||||
|
* if there is only 1 mode under a pb_type, it will be the default
|
||||||
|
* physical mode for this pb_type
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void rec_infer_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* We do not check any primitive pb_type */
|
||||||
|
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For non-primitive pb_type:
|
||||||
|
* - if there is only one mode, it will be the physical mode
|
||||||
|
* we just need to make sure that we do not repeatedly annotate this
|
||||||
|
* - if there are multiple modes, we should be able to find a physical mode
|
||||||
|
* and then go recursively
|
||||||
|
*/
|
||||||
|
t_mode* physical_mode = nullptr;
|
||||||
|
|
||||||
|
if (1 == cur_pb_type->num_modes) {
|
||||||
|
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||||
|
/* Not assigned by explicit annotation, we should infer here */
|
||||||
|
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
|
||||||
|
VTR_LOG("Implicitly infer physical mode '%s' for pb_type '%s'\n",
|
||||||
|
cur_pb_type->modes[0].name, cur_pb_type->name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(1 < cur_pb_type->num_modes);
|
||||||
|
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||||
|
/* Not assigned by explicit annotation, we should infer here */
|
||||||
|
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
|
||||||
|
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
|
||||||
|
cur_pb_type->name);
|
||||||
|
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the physical mode from annotation */
|
||||||
|
physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
|
||||||
|
|
||||||
|
VTR_ASSERT(nullptr != physical_mode);
|
||||||
|
|
||||||
|
/* Traverse the pb_type children under the physical mode */
|
||||||
|
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
|
||||||
|
rec_infer_vpr_physical_pb_mode_annotation(&(physical_mode->pb_type_children[ichild]),
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will infer the physical mode for each multi-mode
|
||||||
|
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* The following rule is applied:
|
||||||
|
* if there is only 1 mode under a pb_type, it will be the default
|
||||||
|
* physical mode for this pb_type
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* This function must be executed AFTER the function
|
||||||
|
* build_vpr_physical_pb_mode_explicit_annotation()
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void build_vpr_physical_pb_mode_implicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rec_infer_vpr_physical_pb_mode_annotation(lb_type.pb_type, vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will recursively traverse pb_type graph to ensure
|
||||||
|
* 1. there is only a physical mode under each pb_type
|
||||||
|
* 2. physical mode appears only when its parent is a physical mode.
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void rec_check_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
|
||||||
|
const bool& expect_physical_mode,
|
||||||
|
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||||
|
size_t& num_err) {
|
||||||
|
/* We do not check any primitive pb_type */
|
||||||
|
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For non-primitive pb_type:
|
||||||
|
* - If we expect a physical mode to exist under this pb_type
|
||||||
|
* we should be able to find one in the annoation
|
||||||
|
* - If we do NOT expect a physical mode, make sure we find
|
||||||
|
* nothing in the annotation
|
||||||
|
*/
|
||||||
|
if (true == expect_physical_mode) {
|
||||||
|
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||||
|
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
|
||||||
|
cur_pb_type->name);
|
||||||
|
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||||
|
num_err++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT_SAFE(false == expect_physical_mode);
|
||||||
|
if (nullptr != vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||||
|
VTR_LOG_ERROR("Find a physical mode '%s' for pb_type '%s' which is not under any physical mode!\n",
|
||||||
|
vpr_pb_type_annotation.physical_mode(cur_pb_type)->name,
|
||||||
|
cur_pb_type->name);
|
||||||
|
num_err++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traverse all the modes
|
||||||
|
* - for pb_type children under a physical mode, we expect an physical mode
|
||||||
|
* - for pb_type children under non-physical mode, we expect no physical mode
|
||||||
|
*/
|
||||||
|
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
||||||
|
bool expect_child_physical_mode = false;
|
||||||
|
if (&(cur_pb_type->modes[imode]) == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
||||||
|
expect_child_physical_mode = true && expect_physical_mode;
|
||||||
|
}
|
||||||
|
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
||||||
|
rec_check_vpr_physical_pb_mode_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
||||||
|
expect_child_physical_mode, vpr_pb_type_annotation,
|
||||||
|
num_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will check the physical mode annotation for
|
||||||
|
* each pb_type in the device
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
size_t num_err = 0;
|
||||||
|
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Top pb_type should always has a physical mode! */
|
||||||
|
rec_check_vpr_physical_pb_mode_annotation(lb_type.pb_type, true, vpr_pb_type_annotation, num_err);
|
||||||
|
}
|
||||||
|
if (0 == num_err) {
|
||||||
|
VTR_LOG("Check physical mode annotation for pb_types passed.\n");
|
||||||
|
} else {
|
||||||
|
VTR_LOG("Check physical mode annotation for pb_types failed with %ld errors!\n",
|
||||||
|
num_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function aims to make a pair of operating and physical
|
||||||
|
* pb_types:
|
||||||
|
* - In addition to pairing the pb_types, it will pair the ports of the pb_types
|
||||||
|
* - For the ports which are explicited annotated as physical pin mapping
|
||||||
|
* in the pb_type annotation.
|
||||||
|
* We will check the port range and create a pair
|
||||||
|
* - For the ports which are not specified in the pb_type annotation
|
||||||
|
* we assume their physical ports share the same as the operating ports
|
||||||
|
* We will try to find a port in the physical pb_type and check the port range
|
||||||
|
* If found, we will create a pair
|
||||||
|
* - All the pairs will be updated in vpr_pb_type_annotation
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
bool pair_operating_and_physical_pb_types(t_pb_type* operating_pb_type,
|
||||||
|
t_pb_type* physical_pb_type,
|
||||||
|
const PbTypeAnnotation& pb_type_annotation,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Reach here, we should have valid operating and physical pb_types */
|
||||||
|
VTR_ASSERT((nullptr != operating_pb_type) && (nullptr != physical_pb_type));
|
||||||
|
|
||||||
|
/* Iterate over the ports under the operating pb_type
|
||||||
|
* For each pin, we will try to find its physical port in the pb_type_annotation
|
||||||
|
* if not found, we assume that the physical port is the same as the operating pb_port
|
||||||
|
*/
|
||||||
|
for (t_port* operating_pb_port : pb_type_ports(operating_pb_type)) {
|
||||||
|
/* Try to find the port in the pb_type_annotation */
|
||||||
|
BasicPort expected_physical_pb_port = pb_type_annotation.physical_pb_type_port(std::string(operating_pb_port->name));
|
||||||
|
if (true == expected_physical_pb_port.get_name().empty()) {
|
||||||
|
/* Not found, we reset the port information to be consistent as the operating pb_port */
|
||||||
|
expected_physical_pb_port.set_name(std::string(operating_pb_port->name));
|
||||||
|
expected_physical_pb_port.set_width(operating_pb_port->num_pins);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find the expected port in the physical pb_type */
|
||||||
|
t_port* physical_pb_port = find_pb_type_port(physical_pb_type, expected_physical_pb_port.get_name());
|
||||||
|
/* Not found, mapping fails */
|
||||||
|
if (nullptr == physical_pb_port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* If the port range does not match, mapping fails */
|
||||||
|
if (false == expected_physical_pb_port.contained(BasicPort(physical_pb_port->name, physical_pb_port->num_pins))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Now, port mapping should succeed, we update the vpr_pb_type_annotation */
|
||||||
|
vpr_pb_type_annotation.add_physical_pb_port(operating_pb_port, physical_pb_port);
|
||||||
|
vpr_pb_type_annotation.add_physical_pb_port_range(operating_pb_port, expected_physical_pb_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, pb_type mapping should succeed, we update the vpr_pb_type_annotation */
|
||||||
|
vpr_pb_type_annotation.add_physical_pb_type(operating_pb_type, physical_pb_type);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will identify the physical pb_type for each operating
|
||||||
|
* pb_type in VPR pb_type graph by following the explicit definition
|
||||||
|
* in OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - This function should be executed only AFTER the physical mode
|
||||||
|
* annotation is completed
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void build_vpr_physical_pb_type_explicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
const Arch& openfpga_arch,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Walk through the pb_type annotation stored in the openfpga arch */
|
||||||
|
for (const PbTypeAnnotation& pb_type_annotation : openfpga_arch.pb_type_annotations) {
|
||||||
|
/* Since our target is to annotate the operating pb_type tp physical pb_type
|
||||||
|
* we can skip those annotation only for physical pb_type
|
||||||
|
*/
|
||||||
|
if (true == pb_type_annotation.is_physical_pb_type()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VTR_ASSERT(true == pb_type_annotation.is_operating_pb_type());
|
||||||
|
|
||||||
|
/* Collect the information about the full hierarchy of operating pb_type to be annotated */
|
||||||
|
std::vector<std::string> target_op_pb_type_names;
|
||||||
|
std::vector<std::string> target_op_pb_mode_names;
|
||||||
|
|
||||||
|
target_op_pb_type_names = pb_type_annotation.operating_parent_pb_type_names();
|
||||||
|
target_op_pb_type_names.push_back(pb_type_annotation.operating_pb_type_name());
|
||||||
|
target_op_pb_mode_names = pb_type_annotation.operating_parent_mode_names();
|
||||||
|
|
||||||
|
/* Collect the information about the full hierarchy of physical pb_type to be annotated */
|
||||||
|
std::vector<std::string> target_phy_pb_type_names;
|
||||||
|
std::vector<std::string> target_phy_pb_mode_names;
|
||||||
|
|
||||||
|
target_phy_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
|
||||||
|
target_phy_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
|
||||||
|
target_phy_pb_mode_names = pb_type_annotation.physical_parent_mode_names();
|
||||||
|
|
||||||
|
/* We must have at least one pb_type in the list */
|
||||||
|
VTR_ASSERT_SAFE(0 < target_op_pb_type_names.size());
|
||||||
|
VTR_ASSERT_SAFE(0 < target_phy_pb_type_names.size());
|
||||||
|
|
||||||
|
/* Pb type information are located at the logic_block_types in the device context of VPR
|
||||||
|
* We iterate over the vectors and find the pb_type matches the parent_pb_type_name
|
||||||
|
*/
|
||||||
|
bool link_success = false;
|
||||||
|
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Check the name of the top-level pb_type, if it does not match, we can bypass */
|
||||||
|
if (target_op_pb_type_names[0] != std::string(lb_type.pb_type->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Match the name in the top-level, we go further to search the operating as well as
|
||||||
|
* physical pb_types in the graph */
|
||||||
|
t_pb_type* target_op_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_op_pb_type_names,
|
||||||
|
target_op_pb_mode_names);
|
||||||
|
if (nullptr == target_op_pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_pb_type* target_phy_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_phy_pb_type_names,
|
||||||
|
target_phy_pb_mode_names);
|
||||||
|
if (nullptr == target_phy_pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Both operating and physical pb_type have been found,
|
||||||
|
* we update the annotation by assigning the physical mode
|
||||||
|
*/
|
||||||
|
if (true == pair_operating_and_physical_pb_types(target_op_pb_type, target_phy_pb_type,
|
||||||
|
pb_type_annotation, vpr_pb_type_annotation)) {
|
||||||
|
|
||||||
|
/* Give a message */
|
||||||
|
VTR_LOG("Annotate operating pb_type '%s' to its physical pb_type '%s'\n",
|
||||||
|
target_op_pb_type->name, target_phy_pb_type->name);
|
||||||
|
|
||||||
|
link_success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false == link_success) {
|
||||||
|
/* Not found, error out! */
|
||||||
|
VTR_LOG_ERROR("Unable to pair the operating pb_type '%s' to its physical pb_type '%s'!\n",
|
||||||
|
target_op_pb_type_names.back().c_str(),
|
||||||
|
target_phy_pb_type_names.back().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function aims to pair a physical pb_type to itself
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
bool self_pair_physical_pb_types(t_pb_type* physical_pb_type,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Reach here, we should have valid physical pb_types */
|
||||||
|
VTR_ASSERT(nullptr != physical_pb_type);
|
||||||
|
|
||||||
|
/* Iterate over the ports under the operating pb_type
|
||||||
|
* For each pin, we will try to find its physical port in the pb_type_annotation
|
||||||
|
* if not found, we assume that the physical port is the same as the operating pb_port
|
||||||
|
*/
|
||||||
|
for (t_port* physical_pb_port : pb_type_ports(physical_pb_type)) {
|
||||||
|
BasicPort physical_port_range(physical_pb_port->name, physical_pb_port->num_pins);
|
||||||
|
vpr_pb_type_annotation.add_physical_pb_port(physical_pb_port, physical_pb_port);
|
||||||
|
vpr_pb_type_annotation.add_physical_pb_port_range(physical_pb_port, physical_port_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, pb_type mapping should succeed, we update the vpr_pb_type_annotation */
|
||||||
|
vpr_pb_type_annotation.add_physical_pb_type(physical_pb_type, physical_pb_type);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will recursively visit all the pb_type from the top
|
||||||
|
* pb_type in the graph (only in the physical mode) and infer the
|
||||||
|
* physical pb_type
|
||||||
|
* This is mainly applied to single-mode pb_type graphs, where the
|
||||||
|
* physical pb_type should be pb_type itself
|
||||||
|
* We can infer this and save the explicit annotation required by users
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void rec_infer_vpr_physical_pb_type_annotation(t_pb_type* cur_pb_type,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Physical pb_type is mainly for the primitive pb_type */
|
||||||
|
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||||
|
/* If the physical pb_type has been mapped, we can skip it */
|
||||||
|
if (nullptr != vpr_pb_type_annotation.physical_pb_type(cur_pb_type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Create the pair here */
|
||||||
|
if (true == self_pair_physical_pb_types(cur_pb_type, vpr_pb_type_annotation)) {
|
||||||
|
/* Give a message */
|
||||||
|
VTR_LOG("Implicitly infer the physical pb_type for pb_type '%s' itself\n",
|
||||||
|
cur_pb_type->name);
|
||||||
|
} else {
|
||||||
|
VTR_LOG_ERROR("Unable to infer the physical pb_type for pb_type '%s' itself!\n",
|
||||||
|
cur_pb_type->name);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the physical mode from annotation */
|
||||||
|
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
|
||||||
|
|
||||||
|
VTR_ASSERT(nullptr != physical_mode);
|
||||||
|
|
||||||
|
/* Traverse the pb_type children under the physical mode */
|
||||||
|
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
|
||||||
|
rec_infer_vpr_physical_pb_type_annotation(&(physical_mode->pb_type_children[ichild]),
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will infer the physical pb_type for each operating
|
||||||
|
* pb_type in VPR pb_type graph which have not been explicitedly defined
|
||||||
|
* in OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - This function should be executed only AFTER the physical mode
|
||||||
|
* annotation is completed
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void build_vpr_physical_pb_type_implicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rec_infer_vpr_physical_pb_type_annotation(lb_type.pb_type, vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will check
|
||||||
|
* - if a primitive pb_type has been mapped to a physical pb_type
|
||||||
|
* - if every port of the pb_type have been linked a port of a physical pb_type
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void check_vpr_physical_primitive_pb_type_annotation(t_pb_type* cur_pb_type,
|
||||||
|
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||||
|
size_t& num_err) {
|
||||||
|
if (nullptr == vpr_pb_type_annotation.physical_pb_type(cur_pb_type)) {
|
||||||
|
VTR_LOG_ERROR("Find a pb_type '%s' which has not been mapped to any physical pb_type!\n",
|
||||||
|
cur_pb_type->name);
|
||||||
|
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||||
|
num_err++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we need to check each port of the pb_type */
|
||||||
|
for (t_port* pb_port : pb_type_ports(cur_pb_type)) {
|
||||||
|
if (nullptr == vpr_pb_type_annotation.physical_pb_port(pb_port)) {
|
||||||
|
VTR_LOG_ERROR("Find a port '%s' of pb_type '%s' which has not been mapped to any physical port!\n",
|
||||||
|
pb_port->name, cur_pb_type->name);
|
||||||
|
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
||||||
|
num_err++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will recursively traverse pb_type graph to ensure
|
||||||
|
* 1. there is only a physical mode under each pb_type
|
||||||
|
* 2. physical mode appears only when its parent is a physical mode.
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void rec_check_vpr_physical_pb_type_annotation(t_pb_type* cur_pb_type,
|
||||||
|
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
||||||
|
size_t& num_err) {
|
||||||
|
/* Primitive pb_type should always been binded to a physical pb_type */
|
||||||
|
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||||
|
check_vpr_physical_primitive_pb_type_annotation(cur_pb_type, vpr_pb_type_annotation, num_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traverse all the modes
|
||||||
|
* - for pb_type children under a physical mode, we expect an physical mode
|
||||||
|
* - for pb_type children under non-physical mode, we expect no physical mode
|
||||||
|
*/
|
||||||
|
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
||||||
|
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
||||||
|
rec_check_vpr_physical_pb_type_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
||||||
|
vpr_pb_type_annotation,
|
||||||
|
num_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will check the physical pb_type annotation for
|
||||||
|
* each pb_type in the device
|
||||||
|
* Every pb_type should have been linked to a physical pb_type
|
||||||
|
* and every port of the pb_type have been linked a port of a physical pb_type
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void check_vpr_physical_pb_type_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
size_t num_err = 0;
|
||||||
|
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Top pb_type should always has a physical mode! */
|
||||||
|
rec_check_vpr_physical_pb_type_annotation(lb_type.pb_type, vpr_pb_type_annotation, num_err);
|
||||||
|
}
|
||||||
|
if (0 == num_err) {
|
||||||
|
VTR_LOG("Check physical pb_type annotation for pb_types passed.\n");
|
||||||
|
} else {
|
||||||
|
VTR_LOG("Check physical pb_type annotation for pb_types failed with %ld errors!\n",
|
||||||
|
num_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function aims to link a physical pb_type to a valid circuit model
|
||||||
|
* in the circuit library
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
bool link_physical_pb_type_to_circuit_model(t_pb_type* physical_pb_type,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const PbTypeAnnotation& pb_type_annotation,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Reach here, we should have valid operating and physical pb_types */
|
||||||
|
VTR_ASSERT(nullptr != physical_pb_type);
|
||||||
|
|
||||||
|
/* This must be a physical pb_type according to our annotation! */
|
||||||
|
if (false == vpr_pb_type_annotation.is_physical_pb_type(physical_pb_type)) {
|
||||||
|
VTR_LOG_ERROR("An operating pb_type '%s' is not allowed to be linked to any circuit model!\n",
|
||||||
|
physical_pb_type->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string pb_type_circuit_model_name = pb_type_annotation.circuit_model_name();
|
||||||
|
CircuitModelId circuit_model_id = circuit_lib.model(pb_type_circuit_model_name);
|
||||||
|
|
||||||
|
if (CircuitModelId::INVALID() == circuit_model_id) {
|
||||||
|
VTR_LOG_ERROR("Unable to find a circuit model '%s' for physical pb_type '%s'!\n",
|
||||||
|
pb_type_circuit_model_name.c_str(),
|
||||||
|
physical_pb_type->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now the circuit model is valid, update the vpr_pb_type_annotation */
|
||||||
|
vpr_pb_type_annotation.add_pb_type_circuit_model(physical_pb_type, circuit_model_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function aims to link an interconnect of a physical mode of
|
||||||
|
* a pb_type to a valid circuit model in the circuit library
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
bool link_physical_pb_interconnect_to_circuit_model(t_pb_type* physical_pb_type,
|
||||||
|
const std::string& interconnect_name,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const PbTypeAnnotation& pb_type_annotation,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* The physical pb_type should NOT be a primitive, otherwise it should never contain any interconnect */
|
||||||
|
if (true == is_primitive_pb_type(physical_pb_type)) {
|
||||||
|
VTR_LOG_ERROR("Link interconnect to circuit model is not allowed for a primitive pb_type '%s'!\n",
|
||||||
|
physical_pb_type->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the physical mode from annotation */
|
||||||
|
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(physical_pb_type);
|
||||||
|
|
||||||
|
VTR_ASSERT(nullptr != physical_mode);
|
||||||
|
|
||||||
|
/* Find the interconnect name under the physical mode of a physical pb_type */
|
||||||
|
t_interconnect* pb_interc = find_pb_mode_interconnect(physical_mode, interconnect_name.c_str());
|
||||||
|
|
||||||
|
if (nullptr == pb_interc) {
|
||||||
|
VTR_LOG_ERROR("Unable to find interconnect '%s' under physical mode '%s' of pb_type '%s'!\n",
|
||||||
|
interconnect_name.c_str(),
|
||||||
|
physical_mode->name,
|
||||||
|
physical_pb_type->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find the circuit model name */
|
||||||
|
std::string pb_type_circuit_model_name = pb_type_annotation.interconnect_circuit_model_name(interconnect_name);
|
||||||
|
CircuitModelId circuit_model_id = circuit_lib.model(pb_type_circuit_model_name);
|
||||||
|
|
||||||
|
if (CircuitModelId::INVALID() == circuit_model_id) {
|
||||||
|
VTR_LOG_ERROR("Unable to find a circuit model '%s' for interconnect '%s' under physical mode '%s' of pb_type '%s'!\n",
|
||||||
|
pb_type_circuit_model_name.c_str(),
|
||||||
|
interconnect_name.c_str(),
|
||||||
|
physical_mode->name,
|
||||||
|
physical_pb_type->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now the circuit model is valid, update the vpr_pb_type_annotation */
|
||||||
|
vpr_pb_type_annotation.add_interconnect_circuit_model(pb_interc, circuit_model_id);
|
||||||
|
|
||||||
|
VTR_LOG("Bind pb_type '%s' physical mode '%s' interconnect '%s' to circuit model '%s'\n",
|
||||||
|
physical_pb_type->name,
|
||||||
|
physical_mode->name,
|
||||||
|
pb_interc->name,
|
||||||
|
circuit_lib.model_name(circuit_model_id).c_str());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will link
|
||||||
|
* - pb_type to circuit models in circuit library by following
|
||||||
|
* the explicit definition in OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - This function should be executed only AFTER the physical mode and
|
||||||
|
* physical pb_type annotation is completed
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void link_vpr_pb_type_to_circuit_model_explicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
const Arch& openfpga_arch,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Walk through the pb_type annotation stored in the openfpga arch */
|
||||||
|
for (const PbTypeAnnotation& pb_type_annotation : openfpga_arch.pb_type_annotations) {
|
||||||
|
/* Since our target is to annotate the circuti model for physical pb_type
|
||||||
|
* we can skip those annotation only for operating pb_type
|
||||||
|
*/
|
||||||
|
if (true == pb_type_annotation.is_operating_pb_type()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true == pb_type_annotation.circuit_model_name().empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VTR_ASSERT(true == pb_type_annotation.is_physical_pb_type());
|
||||||
|
|
||||||
|
/* Collect the information about the full hierarchy of physical pb_type to be annotated */
|
||||||
|
std::vector<std::string> target_phy_pb_type_names;
|
||||||
|
std::vector<std::string> target_phy_pb_mode_names;
|
||||||
|
|
||||||
|
target_phy_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
|
||||||
|
target_phy_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
|
||||||
|
target_phy_pb_mode_names = pb_type_annotation.physical_parent_mode_names();
|
||||||
|
|
||||||
|
/* We must have at least one pb_type in the list */
|
||||||
|
VTR_ASSERT_SAFE(0 < target_phy_pb_type_names.size());
|
||||||
|
|
||||||
|
/* Pb type information are located at the logic_block_types in the device context of VPR
|
||||||
|
* We iterate over the vectors and find the pb_type matches the parent_pb_type_name
|
||||||
|
*/
|
||||||
|
bool link_success = false;
|
||||||
|
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Check the name of the top-level pb_type, if it does not match, we can bypass */
|
||||||
|
if (target_phy_pb_type_names[0] != std::string(lb_type.pb_type->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Match the name in the top-level, we go further to search the operating as well as
|
||||||
|
* physical pb_types in the graph */
|
||||||
|
t_pb_type* target_phy_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_phy_pb_type_names,
|
||||||
|
target_phy_pb_mode_names);
|
||||||
|
if (nullptr == target_phy_pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only try to bind pb_type to circuit model when it is defined by users */
|
||||||
|
if (true == link_physical_pb_type_to_circuit_model(target_phy_pb_type, openfpga_arch.circuit_lib,
|
||||||
|
pb_type_annotation, vpr_pb_type_annotation)) {
|
||||||
|
/* Give a message */
|
||||||
|
VTR_LOG("Bind physical pb_type '%s' to its circuit model '%s'\n",
|
||||||
|
target_phy_pb_type->name,
|
||||||
|
openfpga_arch.circuit_lib.model_name(vpr_pb_type_annotation.pb_type_circuit_model(target_phy_pb_type)).c_str());
|
||||||
|
|
||||||
|
link_success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false == link_success) {
|
||||||
|
/* Not found, error out! */
|
||||||
|
VTR_LOG_ERROR("Unable to bind physical pb_type '%s' to circuit model '%s'!\n",
|
||||||
|
target_phy_pb_type_names.back().c_str(),
|
||||||
|
pb_type_annotation.circuit_model_name().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will link
|
||||||
|
* - interconnect of pb_type to circuit models in circuit library by following
|
||||||
|
* the explicit definition in OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - This function should be executed only AFTER the physical mode and
|
||||||
|
* physical pb_type annotation is completed
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void link_vpr_pb_interconnect_to_circuit_model_explicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
const Arch& openfpga_arch,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* Walk through the pb_type annotation stored in the openfpga arch */
|
||||||
|
for (const PbTypeAnnotation& pb_type_annotation : openfpga_arch.pb_type_annotations) {
|
||||||
|
/* Since our target is to annotate the circuti model for physical pb_type
|
||||||
|
* we can skip those annotation only for operating pb_type
|
||||||
|
*/
|
||||||
|
if (true == pb_type_annotation.is_operating_pb_type()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == pb_type_annotation.interconnect_names().size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VTR_ASSERT(true == pb_type_annotation.is_physical_pb_type());
|
||||||
|
|
||||||
|
/* Collect the information about the full hierarchy of physical pb_type to be annotated */
|
||||||
|
std::vector<std::string> target_phy_pb_type_names;
|
||||||
|
std::vector<std::string> target_phy_pb_mode_names;
|
||||||
|
|
||||||
|
target_phy_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
|
||||||
|
target_phy_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
|
||||||
|
target_phy_pb_mode_names = pb_type_annotation.physical_parent_mode_names();
|
||||||
|
|
||||||
|
/* We must have at least one pb_type in the list */
|
||||||
|
VTR_ASSERT_SAFE(0 < target_phy_pb_type_names.size());
|
||||||
|
|
||||||
|
/* Pb type information are located at the logic_block_types in the device context of VPR
|
||||||
|
* We iterate over the vectors and find the pb_type matches the parent_pb_type_name
|
||||||
|
*/
|
||||||
|
bool link_success = true;
|
||||||
|
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Check the name of the top-level pb_type, if it does not match, we can bypass */
|
||||||
|
if (target_phy_pb_type_names[0] != std::string(lb_type.pb_type->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Match the name in the top-level, we go further to search the operating as well as
|
||||||
|
* physical pb_types in the graph */
|
||||||
|
t_pb_type* target_phy_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_phy_pb_type_names,
|
||||||
|
target_phy_pb_mode_names);
|
||||||
|
if (nullptr == target_phy_pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only try to bind interconnect to circuit model when it is defined by users */
|
||||||
|
for (const std::string& interc_name : pb_type_annotation.interconnect_names()) {
|
||||||
|
if (false == link_physical_pb_interconnect_to_circuit_model(target_phy_pb_type, interc_name, openfpga_arch.circuit_lib,
|
||||||
|
pb_type_annotation, vpr_pb_type_annotation)) {
|
||||||
|
VTR_LOG_ERROR("Unable to bind pb_type '%s' interconnect '%s' to circuit model '%s'!\n",
|
||||||
|
target_phy_pb_type_names.back().c_str(),
|
||||||
|
interc_name.c_str(),
|
||||||
|
pb_type_annotation.circuit_model_name().c_str());
|
||||||
|
link_success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false == link_success) {
|
||||||
|
/* Not found, error out! */
|
||||||
|
VTR_LOG_ERROR("Unable to bind interconnects of physical pb_type '%s' to circuit model '%s'!\n",
|
||||||
|
target_phy_pb_type_names.back().c_str(),
|
||||||
|
pb_type_annotation.circuit_model_name().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will recursively visit all the pb_type from the top
|
||||||
|
* pb_type in the graph and infer the circuit model for physical mode
|
||||||
|
* of pb_types in VPR pb_type graph without OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* Because only the interconnect in physical modes need circuit model
|
||||||
|
* annotation, we will skip all the operating modes here
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - This function will automatically infer the type of circuit model
|
||||||
|
* that is required and find the default circuit model in the type
|
||||||
|
* - Interconnect type to Circuit mode type assumption:
|
||||||
|
* - MUX_INTERC -> CIRCUIT_MODEL_MUX
|
||||||
|
* - DIRECT_INTERC -> CIRCUIT_MODEL_WIRE
|
||||||
|
* - COMPLETE_INTERC (single input) -> CIRCUIT_MODEL_WIRE
|
||||||
|
* - COMPLETE_INTERC (multiple input pins) -> CIRCUIT_MODEL_MUX
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void rec_infer_vpr_pb_interconnect_circuit_model_annotation(t_pb_type* cur_pb_type,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
/* We do not check any primitive pb_type */
|
||||||
|
if (true == is_primitive_pb_type(cur_pb_type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the physical mode from annotation */
|
||||||
|
t_mode* physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
|
||||||
|
|
||||||
|
VTR_ASSERT(nullptr != physical_mode);
|
||||||
|
|
||||||
|
/* Annotate the circuit model for each interconnect under this physical mode */
|
||||||
|
for (t_interconnect* pb_interc : pb_mode_interconnects(physical_mode)) {
|
||||||
|
/* If the interconnect has been annotated, we skip it */
|
||||||
|
if (CircuitModelId::INVALID() != vpr_pb_type_annotation.interconnect_circuit_model(pb_interc)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Infer the circuit model type for a given interconnect */
|
||||||
|
e_circuit_model_type circuit_model_type = pb_interconnect_require_circuit_model_type(vpr_pb_type_annotation.interconnect_physical_type(pb_interc));
|
||||||
|
/* Try to find a default circuit model from the circuit library */
|
||||||
|
CircuitModelId default_circuit_model = circuit_lib.default_model(circuit_model_type);
|
||||||
|
/* Update the annotation if the model id is valid */
|
||||||
|
if (CircuitModelId::INVALID() == default_circuit_model) {
|
||||||
|
VTR_LOG_ERROR("Unable to infer a circuit model for interconnect '%s' under physical mode '%s' of pb_type '%s'!\n",
|
||||||
|
pb_interc->name,
|
||||||
|
physical_mode->name,
|
||||||
|
cur_pb_type->name);
|
||||||
|
}
|
||||||
|
vpr_pb_type_annotation.add_interconnect_circuit_model(pb_interc, default_circuit_model);
|
||||||
|
VTR_LOG("Implicitly infer a circuit model '%s' for interconnect '%s' under physical mode '%s' of pb_type '%s'\n",
|
||||||
|
circuit_lib.model_name(default_circuit_model).c_str(),
|
||||||
|
pb_interc->name,
|
||||||
|
physical_mode->name,
|
||||||
|
cur_pb_type->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traverse the pb_type children under the physical mode */
|
||||||
|
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
|
||||||
|
rec_infer_vpr_pb_interconnect_circuit_model_annotation(&(physical_mode->pb_type_children[ichild]),
|
||||||
|
circuit_lib, vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will infer the circuit model for each interconnect
|
||||||
|
* under a physical mode of a pb_type in VPR pb_type graph without
|
||||||
|
* OpenFPGA architecture XML
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* This function must be executed AFTER the function
|
||||||
|
* build_vpr_physical_pb_mode_explicit_annotation()
|
||||||
|
* build_vpr_physical_pb_mode_implicit_annotation()
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void link_vpr_pb_interconnect_to_circuit_model_implicit_annotation(const DeviceContext& vpr_device_ctx,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
||||||
|
/* By pass nullptr for pb_type head */
|
||||||
|
if (nullptr == lb_type.pb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rec_infer_vpr_pb_interconnect_circuit_model_annotation(lb_type.pb_type, circuit_lib, vpr_pb_type_annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Top-level function to link openfpga architecture to VPR, including:
|
||||||
|
* - physical pb_type
|
||||||
|
* - circuit models for pb_type, pb interconnect
|
||||||
|
*******************************************************************/
|
||||||
|
void annotate_pb_types(const DeviceContext& vpr_device_ctx,
|
||||||
|
const Arch& openfpga_arch,
|
||||||
|
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||||
|
|
||||||
|
/* Annotate physical mode to pb_type in the VPR pb_type graph */
|
||||||
|
build_vpr_physical_pb_mode_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
|
||||||
|
build_vpr_physical_pb_mode_implicit_annotation(vpr_device_ctx,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
|
||||||
|
check_vpr_physical_pb_mode_annotation(vpr_device_ctx,
|
||||||
|
const_cast<const VprPbTypeAnnotation&>(vpr_pb_type_annotation));
|
||||||
|
|
||||||
|
/* Annotate the physical type for each interconnect under physical modes
|
||||||
|
* Must run AFTER physical mode annotation is done and
|
||||||
|
* BEFORE inferring the circuit model for interconnect
|
||||||
|
*/
|
||||||
|
annotate_pb_graph_interconnect_physical_type(vpr_device_ctx,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
|
||||||
|
/* Annotate physical pb_types to operating pb_type in the VPR pb_type graph */
|
||||||
|
build_vpr_physical_pb_type_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
|
||||||
|
build_vpr_physical_pb_type_implicit_annotation(vpr_device_ctx,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
|
||||||
|
check_vpr_physical_pb_type_annotation(vpr_device_ctx,
|
||||||
|
const_cast<const VprPbTypeAnnotation&>(vpr_pb_type_annotation));
|
||||||
|
|
||||||
|
/* Link
|
||||||
|
* - physical pb_type to circuit model
|
||||||
|
* - interconnect of physical pb_type to circuit model
|
||||||
|
*/
|
||||||
|
/* TODO: link the pb_type port to circuit model port here! */
|
||||||
|
link_vpr_pb_type_to_circuit_model_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
link_vpr_pb_interconnect_to_circuit_model_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
link_vpr_pb_interconnect_to_circuit_model_implicit_annotation(vpr_device_ctx, openfpga_arch.circuit_lib,
|
||||||
|
vpr_pb_type_annotation);
|
||||||
|
|
||||||
|
/* Link physical pb_type to mode_bits */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -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
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include "vpr_pb_type_annotation.h"
|
#include "vpr_pb_type_annotation.h"
|
||||||
#include "pb_type_utils.h"
|
#include "pb_type_utils.h"
|
||||||
|
#include "annotate_pb_types.h"
|
||||||
|
#include "annotate_pb_graph.h"
|
||||||
#include "openfpga_link_arch.h"
|
#include "openfpga_link_arch.h"
|
||||||
|
|
||||||
/* Include global variables of VPR */
|
/* Include global variables of VPR */
|
||||||
|
@ -17,324 +19,25 @@
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* This function will traverse pb_type graph from its top to find
|
|
||||||
* a pb_type with a given name as well as its hierarchy
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
|
|
||||||
const std::vector<std::string>& target_pb_type_names,
|
|
||||||
const std::vector<std::string>& target_pb_mode_names) {
|
|
||||||
/* Ensure that number of parent names and modes matches */
|
|
||||||
VTR_ASSERT_SAFE(target_pb_type_names.size() == target_pb_mode_names.size() + 1);
|
|
||||||
|
|
||||||
t_pb_type* cur_pb_type = top_pb_type;
|
|
||||||
|
|
||||||
/* If the top pb_type is what we want, we can return here */
|
|
||||||
if (1 == target_pb_type_names.size()) {
|
|
||||||
if (target_pb_type_names[0] == std::string(top_pb_type->name)) {
|
|
||||||
return top_pb_type;
|
|
||||||
}
|
|
||||||
/* Not match, return null pointer */
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We start from the first element of the parent names and parent modes.
|
|
||||||
* If the pb_type does not match in name, we fail
|
|
||||||
* If we cannot find a mode match the name, we fail
|
|
||||||
*/
|
|
||||||
for (size_t i = 0; i < target_pb_type_names.size() - 1; ++i) {
|
|
||||||
/* If this level does not match, search fail */
|
|
||||||
if (target_pb_type_names[i] != std::string(cur_pb_type->name)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
/* Find if the mode matches */
|
|
||||||
t_mode* cur_mode = find_pb_type_mode(cur_pb_type, target_pb_mode_names[i].c_str());
|
|
||||||
if (nullptr == cur_mode) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
/* Go to the next level of pb_type */
|
|
||||||
cur_pb_type = find_mode_child_pb_type(cur_mode, target_pb_type_names[i + 1].c_str());
|
|
||||||
if (nullptr == cur_pb_type) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
/* If this is already the last pb_type in the list, this is what we want */
|
|
||||||
if (i == target_pb_type_names.size() - 1) {
|
|
||||||
return cur_pb_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reach here, it means we find nothing */
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* This function will identify the physical pb_type for each multi-mode
|
|
||||||
* pb_type in VPR pb_type graph by following the explicit definition
|
|
||||||
* in OpenFPGA architecture XML
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void build_vpr_physical_pb_mode_explicit_annotation(const DeviceContext& vpr_device_ctx,
|
|
||||||
const Arch& openfpga_arch,
|
|
||||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
|
||||||
/* Walk through the pb_type annotation stored in the openfpga arch */
|
|
||||||
for (const PbTypeAnnotation& pb_type_annotation : openfpga_arch.pb_type_annotations) {
|
|
||||||
/* Since our target is to annotate the physical mode name,
|
|
||||||
* we can skip those has not physical mode defined
|
|
||||||
*/
|
|
||||||
if (true == pb_type_annotation.physical_mode_name().empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Identify if the pb_type is operating or physical,
|
|
||||||
* For operating pb_type, get the full name of operating pb_type
|
|
||||||
* For physical pb_type, get the full name of physical pb_type
|
|
||||||
*/
|
|
||||||
std::vector<std::string> target_pb_type_names;
|
|
||||||
std::vector<std::string> target_pb_mode_names;
|
|
||||||
|
|
||||||
if (true == pb_type_annotation.is_operating_pb_type()) {
|
|
||||||
target_pb_type_names = pb_type_annotation.operating_parent_pb_type_names();
|
|
||||||
target_pb_type_names.push_back(pb_type_annotation.operating_pb_type_name());
|
|
||||||
target_pb_mode_names = pb_type_annotation.operating_parent_mode_names();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true == pb_type_annotation.is_physical_pb_type()) {
|
|
||||||
target_pb_type_names = pb_type_annotation.physical_parent_pb_type_names();
|
|
||||||
target_pb_type_names.push_back(pb_type_annotation.physical_pb_type_name());
|
|
||||||
target_pb_mode_names = pb_type_annotation.physical_parent_mode_names();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We must have at least one pb_type in the list */
|
|
||||||
VTR_ASSERT_SAFE(0 < target_pb_type_names.size());
|
|
||||||
|
|
||||||
/* Pb type information are located at the logic_block_types in the device context of VPR
|
|
||||||
* We iterate over the vectors and find the pb_type matches the parent_pb_type_name
|
|
||||||
*/
|
|
||||||
bool link_success = false;
|
|
||||||
|
|
||||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
|
||||||
/* By pass nullptr for pb_type head */
|
|
||||||
if (nullptr == lb_type.pb_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Check the name of the top-level pb_type, if it does not match, we can bypass */
|
|
||||||
if (target_pb_type_names[0] != std::string(lb_type.pb_type->name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Match the name in the top-level, we go further to search the pb_type in the graph */
|
|
||||||
t_pb_type* target_pb_type = try_find_pb_type_with_given_path(lb_type.pb_type, target_pb_type_names,
|
|
||||||
target_pb_mode_names);
|
|
||||||
if (nullptr == target_pb_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Found, we update the annotation by assigning the physical mode */
|
|
||||||
t_mode* physical_mode = find_pb_type_mode(target_pb_type, pb_type_annotation.physical_mode_name().c_str());
|
|
||||||
vpr_pb_type_annotation.add_pb_type_physical_mode(target_pb_type, physical_mode);
|
|
||||||
|
|
||||||
/* Give a message */
|
|
||||||
VTR_LOG("Annotate pb_type '%s' with physical mode '%s'\n",
|
|
||||||
target_pb_type->name, physical_mode->name);
|
|
||||||
|
|
||||||
link_success = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false == link_success) {
|
|
||||||
/* Not found, error out! */
|
|
||||||
VTR_LOG_ERROR("Unable to find the pb_type '%s' in VPR architecture definition!\n",
|
|
||||||
target_pb_type_names.back().c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* This function will recursively visit all the pb_type from the top
|
|
||||||
* pb_type in the graph and
|
|
||||||
* infer the physical pb_type for each multi-mode
|
|
||||||
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
|
|
||||||
*
|
|
||||||
* The following rule is applied:
|
|
||||||
* if there is only 1 mode under a pb_type, it will be the default
|
|
||||||
* physical mode for this pb_type
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void rec_infer_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
|
|
||||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
|
||||||
/* We do not check any primitive pb_type */
|
|
||||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For non-primitive pb_type:
|
|
||||||
* - if there is only one mode, it will be the physical mode
|
|
||||||
* we just need to make sure that we do not repeatedly annotate this
|
|
||||||
* - if there are multiple modes, we should be able to find a physical mode
|
|
||||||
* and then go recursively
|
|
||||||
*/
|
|
||||||
t_mode* physical_mode = nullptr;
|
|
||||||
|
|
||||||
if (1 == cur_pb_type->num_modes) {
|
|
||||||
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
|
||||||
/* Not assigned by explicit annotation, we should infer here */
|
|
||||||
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
|
|
||||||
VTR_LOG("Implicitly infer physical mode '%s' for pb_type '%s'\n",
|
|
||||||
cur_pb_type->modes[0].name, cur_pb_type->name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT(1 < cur_pb_type->num_modes);
|
|
||||||
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
|
||||||
/* Not assigned by explicit annotation, we should infer here */
|
|
||||||
vpr_pb_type_annotation.add_pb_type_physical_mode(cur_pb_type, &(cur_pb_type->modes[0]));
|
|
||||||
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
|
|
||||||
cur_pb_type->name);
|
|
||||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the physical mode from annotation */
|
|
||||||
physical_mode = vpr_pb_type_annotation.physical_mode(cur_pb_type);
|
|
||||||
|
|
||||||
VTR_ASSERT(nullptr != physical_mode);
|
|
||||||
|
|
||||||
/* Traverse the pb_type children under the physical mode */
|
|
||||||
for (int ichild = 0; ichild < physical_mode->num_pb_type_children; ++ichild) {
|
|
||||||
rec_infer_vpr_physical_pb_mode_annotation(&(physical_mode->pb_type_children[ichild]),
|
|
||||||
vpr_pb_type_annotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* This function will infer the physical pb_type for each multi-mode
|
|
||||||
* pb_type in VPR pb_type graph without OpenFPGA architecture XML
|
|
||||||
*
|
|
||||||
* The following rule is applied:
|
|
||||||
* if there is only 1 mode under a pb_type, it will be the default
|
|
||||||
* physical mode for this pb_type
|
|
||||||
*
|
|
||||||
* Note:
|
|
||||||
* This function must be executed AFTER the function
|
|
||||||
* build_vpr_physical_pb_mode_explicit_annotation()
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void build_vpr_physical_pb_mode_implicit_annotation(const DeviceContext& vpr_device_ctx,
|
|
||||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
|
||||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
|
||||||
/* By pass nullptr for pb_type head */
|
|
||||||
if (nullptr == lb_type.pb_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
rec_infer_vpr_physical_pb_mode_annotation(lb_type.pb_type, vpr_pb_type_annotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* This function will recursively traverse pb_type graph to ensure
|
|
||||||
* 1. there is only a physical mode under each pb_type
|
|
||||||
* 2. physical mode appears only when its parent is a physical mode.
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void rec_check_vpr_physical_pb_mode_annotation(t_pb_type* cur_pb_type,
|
|
||||||
const bool& expect_physical_mode,
|
|
||||||
const VprPbTypeAnnotation& vpr_pb_type_annotation,
|
|
||||||
size_t& num_err) {
|
|
||||||
/* We do not check any primitive pb_type */
|
|
||||||
if (true == is_primitive_pb_type(cur_pb_type)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For non-primitive pb_type:
|
|
||||||
* - If we expect a physical mode to exist under this pb_type
|
|
||||||
* we should be able to find one in the annoation
|
|
||||||
* - If we do NOT expect a physical mode, make sure we find
|
|
||||||
* nothing in the annotation
|
|
||||||
*/
|
|
||||||
if (true == expect_physical_mode) {
|
|
||||||
if (nullptr == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
|
||||||
VTR_LOG_ERROR("Unable to find a physical mode for a multi-mode pb_type '%s'!\n",
|
|
||||||
cur_pb_type->name);
|
|
||||||
VTR_LOG_ERROR("Please specify in the OpenFPGA architecture\n");
|
|
||||||
num_err++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT_SAFE(false == expect_physical_mode);
|
|
||||||
if (nullptr != vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
|
||||||
VTR_LOG_ERROR("Find a physical mode '%s' for pb_type '%s' which is not under any physical mode!\n",
|
|
||||||
vpr_pb_type_annotation.physical_mode(cur_pb_type)->name,
|
|
||||||
cur_pb_type->name);
|
|
||||||
num_err++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Traverse all the modes
|
|
||||||
* - for pb_type children under a physical mode, we expect an physical mode
|
|
||||||
* - for pb_type children under non-physical mode, we expect no physical mode
|
|
||||||
*/
|
|
||||||
for (int imode = 0; imode < cur_pb_type->num_modes; ++imode) {
|
|
||||||
bool expect_child_physical_mode = false;
|
|
||||||
if (&(cur_pb_type->modes[imode]) == vpr_pb_type_annotation.physical_mode(cur_pb_type)) {
|
|
||||||
expect_child_physical_mode = true && expect_physical_mode;
|
|
||||||
}
|
|
||||||
for (int ichild = 0; ichild < cur_pb_type->modes[imode].num_pb_type_children; ++ichild) {
|
|
||||||
rec_check_vpr_physical_pb_mode_annotation(&(cur_pb_type->modes[imode].pb_type_children[ichild]),
|
|
||||||
expect_child_physical_mode, vpr_pb_type_annotation,
|
|
||||||
num_err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* This function will check the physical mode annotation for
|
|
||||||
* each pb_type in the device
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void check_vpr_physical_pb_mode_annotation(const DeviceContext& vpr_device_ctx,
|
|
||||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
|
||||||
size_t num_err = 0;
|
|
||||||
|
|
||||||
for (const t_logical_block_type& lb_type : vpr_device_ctx.logical_block_types) {
|
|
||||||
/* By pass nullptr for pb_type head */
|
|
||||||
if (nullptr == lb_type.pb_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Top pb_type should always has a physical mode! */
|
|
||||||
rec_check_vpr_physical_pb_mode_annotation(lb_type.pb_type, true, vpr_pb_type_annotation, num_err);
|
|
||||||
}
|
|
||||||
if (0 == num_err) {
|
|
||||||
VTR_LOG("Check physical mode annotation for pb_types passed.\n");
|
|
||||||
} else {
|
|
||||||
VTR_LOG("Check physical mode annotation for pb_types failed with %ld errors!\n",
|
|
||||||
num_err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Top-level function to link openfpga architecture to VPR, including:
|
* Top-level function to link openfpga architecture to VPR, including:
|
||||||
* - physical pb_type
|
* - physical pb_type
|
||||||
* - idle pb_type
|
* - mode selection bits for pb_type and pb interconnect
|
||||||
* - circuit models for pb_type, pb interconnect and routing architecture
|
* - 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) {
|
void link_arch(OpenfpgaContext& openfpga_context) {
|
||||||
|
|
||||||
vtr::ScopedStartFinishTimer timer("Link OpenFPGA architecture to VPR architecture");
|
vtr::ScopedStartFinishTimer timer("Link OpenFPGA architecture to VPR architecture");
|
||||||
|
|
||||||
/* Annotate physical pb_type in the VPR pb_type graph */
|
/* Annotate pb_type graphs
|
||||||
build_vpr_physical_pb_mode_explicit_annotation(g_vpr_ctx.device(), openfpga_context.arch(),
|
* - physical pb_type
|
||||||
openfpga_context.mutable_vpr_pb_type_annotation());
|
* - mode selection bits for pb_type and pb interconnect
|
||||||
build_vpr_physical_pb_mode_implicit_annotation(g_vpr_ctx.device(),
|
* - circuit models for pb_type and pb interconnect
|
||||||
openfpga_context.mutable_vpr_pb_type_annotation());
|
*/
|
||||||
|
annotate_pb_types(g_vpr_ctx.device(), openfpga_context.arch(),
|
||||||
check_vpr_physical_pb_mode_annotation(g_vpr_ctx.device(),
|
openfpga_context.mutable_vpr_pb_type_annotation());
|
||||||
openfpga_context.vpr_pb_type_annotation());
|
|
||||||
|
|
||||||
/* Annotate idle pb_type in the VPR pb_type graph */
|
|
||||||
|
|
||||||
/* Link physical pb_type to circuit model */
|
|
||||||
|
|
||||||
/* Link routing architecture to circuit model */
|
/* Link routing architecture to circuit model */
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef OPENFPGA_LINK_ARCH_COMMAND_H
|
#ifndef OPENFPGA_LINK_ARCH_H
|
||||||
#define OPENFPGA_LINK_ARCH_COMMAND_H
|
#define OPENFPGA_LINK_ARCH_H
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Include header files that are required by function declaration
|
* Include header files that are required by function declaration
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes most utilized functions for the pb_graph_node
|
||||||
|
* and pb_graph_pin data structure in the OpenFPGA context
|
||||||
|
*******************************************************************/
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
|
||||||
|
#include "pb_graph_utils.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function aims to find out all the pb_graph_pins that drive
|
||||||
|
* a given pb_graph pin w.r.t. a given interconnect definition
|
||||||
|
*******************************************************************/
|
||||||
|
std::vector<t_pb_graph_pin*> pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin,
|
||||||
|
t_interconnect* selected_interconnect) {
|
||||||
|
std::vector<t_pb_graph_pin*> inputs;
|
||||||
|
|
||||||
|
/* Search the input edges only, stats on the size of MUX we may need (fan-in) */
|
||||||
|
for (int iedge = 0; iedge < pb_graph_pin->num_input_edges; ++iedge) {
|
||||||
|
/* We care the only edges in the selected mode */
|
||||||
|
if (selected_interconnect != pb_graph_pin->input_edges[iedge]->interconnect) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int ipin = 0; ipin < pb_graph_pin->input_edges[iedge]->num_input_pins; ++ipin) {
|
||||||
|
/* Ensure that the pin is unique in the list */
|
||||||
|
if (inputs.end() != std::find(inputs.begin(), inputs.end(), pb_graph_pin->input_edges[iedge]->input_pins[ipin])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Unique pin, push to the vector */
|
||||||
|
inputs.push_back(pb_graph_pin->input_edges[iedge]->input_pins[ipin]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef PB_GRAPH_UTILS_H
|
||||||
|
#define PB_GRAPH_UTILS_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "physical_types.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
std::vector<t_pb_graph_pin*> pb_graph_pin_inputs(t_pb_graph_pin* pb_graph_pin,
|
||||||
|
t_interconnect* selected_interconnect);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,7 +1,9 @@
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* This file includes most utilized functions for the pb_type
|
* This file includes most utilized functions for the t_pb_type,
|
||||||
* and pb_graph_node data structure in the OpenFPGA context
|
* t_mode and t_port data structure in the OpenFPGA context
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
|
#include <map>
|
||||||
|
|
||||||
/* Headers from vtrutil library */
|
/* Headers from vtrutil library */
|
||||||
#include "vtr_assert.h"
|
#include "vtr_assert.h"
|
||||||
#include "vtr_log.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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* With a given pb_type, provide a list of its ports
|
||||||
|
************************************************************************/
|
||||||
|
std::vector<t_port*> pb_type_ports(t_pb_type* pb_type) {
|
||||||
|
std::vector<t_port*> ports;
|
||||||
|
for (int i = 0; i < pb_type->num_ports; ++i) {
|
||||||
|
ports.push_back(&(pb_type->ports[i]));
|
||||||
|
}
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* Find a port for a pb_type with a given name
|
||||||
|
* If not found, return null pointer
|
||||||
|
************************************************************************/
|
||||||
|
t_port* find_pb_type_port(t_pb_type* pb_type, const std::string& port_name) {
|
||||||
|
for (int i = 0; i < pb_type->num_ports; ++i) {
|
||||||
|
if (port_name == std::string(pb_type->ports[i].name)) {
|
||||||
|
return &(pb_type->ports[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will traverse pb_type graph from its top to find
|
||||||
|
* a pb_type with a given name as well as its hierarchy
|
||||||
|
*******************************************************************/
|
||||||
|
t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
|
||||||
|
const std::vector<std::string>& target_pb_type_names,
|
||||||
|
const std::vector<std::string>& target_pb_mode_names) {
|
||||||
|
/* Ensure that number of parent names and modes matches */
|
||||||
|
VTR_ASSERT_SAFE(target_pb_type_names.size() == target_pb_mode_names.size() + 1);
|
||||||
|
|
||||||
|
t_pb_type* cur_pb_type = top_pb_type;
|
||||||
|
|
||||||
|
/* If the top pb_type is what we want, we can return here */
|
||||||
|
if (1 == target_pb_type_names.size()) {
|
||||||
|
if (target_pb_type_names[0] == std::string(top_pb_type->name)) {
|
||||||
|
return top_pb_type;
|
||||||
|
}
|
||||||
|
/* Not match, return null pointer */
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We start from the first element of the parent names and parent modes.
|
||||||
|
* If the pb_type does not match in name, we fail
|
||||||
|
* If we cannot find a mode match the name, we fail
|
||||||
|
*/
|
||||||
|
for (size_t i = 0; i < target_pb_type_names.size() - 1; ++i) {
|
||||||
|
/* If this level does not match, search fail */
|
||||||
|
if (target_pb_type_names[i] != std::string(cur_pb_type->name)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
/* Find if the mode matches */
|
||||||
|
t_mode* cur_mode = find_pb_type_mode(cur_pb_type, target_pb_mode_names[i].c_str());
|
||||||
|
if (nullptr == cur_mode) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
/* Go to the next level of pb_type */
|
||||||
|
cur_pb_type = find_mode_child_pb_type(cur_mode, target_pb_type_names[i + 1].c_str());
|
||||||
|
if (nullptr == cur_pb_type) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
/* If this is already the last pb_type in the list, this is what we want */
|
||||||
|
if (i + 1 == target_pb_type_names.size() - 1) {
|
||||||
|
return cur_pb_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reach here, it means we find nothing */
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will return all the interconnects defined under a mode
|
||||||
|
* of pb_type
|
||||||
|
*******************************************************************/
|
||||||
|
std::vector<t_interconnect*> pb_mode_interconnects(t_mode* pb_mode) {
|
||||||
|
std::vector<t_interconnect*> interc;
|
||||||
|
for (int i = 0; i < pb_mode->num_interconnect; ++i) {
|
||||||
|
interc.push_back(&(pb_mode->interconnect[i]));
|
||||||
|
}
|
||||||
|
return interc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will try to find an interconnect defined under a mode
|
||||||
|
* of pb_type with a given name.
|
||||||
|
* If not found, return null pointer
|
||||||
|
*******************************************************************/
|
||||||
|
t_interconnect* find_pb_mode_interconnect(t_mode* pb_mode, const char* interc_name) {
|
||||||
|
for (int i = 0; i < pb_mode->num_interconnect; ++i) {
|
||||||
|
if (std::string(interc_name) == std::string(pb_mode->interconnect[i].name)) {
|
||||||
|
return &(pb_mode->interconnect[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reach here, it means we find nothing */
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will automatically infer the actual type of an interconnect
|
||||||
|
* that will be used to implement the physical design:
|
||||||
|
* - MUX_INTERC -> MUX_INTERC
|
||||||
|
* - DIRECT_INTERC -> DIRECT_INTERC
|
||||||
|
* - COMPLETE_INTERC (single input) -> DIRECT_INTERC
|
||||||
|
* - COMPLETE_INTERC (multiple input pins) -> MUX_INTERC
|
||||||
|
*******************************************************************/
|
||||||
|
e_interconnect pb_interconnect_physical_type(t_interconnect* pb_interc,
|
||||||
|
const size_t& num_inputs) {
|
||||||
|
/* Check */
|
||||||
|
VTR_ASSERT(nullptr != pb_interc);
|
||||||
|
|
||||||
|
/* Initialize the interconnection type that will be implemented in SPICE netlist*/
|
||||||
|
switch (pb_interc->type) {
|
||||||
|
case DIRECT_INTERC:
|
||||||
|
return DIRECT_INTERC;
|
||||||
|
break;
|
||||||
|
case COMPLETE_INTERC:
|
||||||
|
if (1 == num_inputs) {
|
||||||
|
return DIRECT_INTERC;
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(1 < num_inputs);
|
||||||
|
return MUX_INTERC;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MUX_INTERC:
|
||||||
|
return MUX_INTERC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VTR_LOG_ERROR("Invalid type for interconnection '%s'!\n",
|
||||||
|
pb_interc->name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NUM_INTERC_TYPES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function will automatically infer the actual type of an interconnect
|
||||||
|
* that will be used to implement the physical design:
|
||||||
|
* - MUX_INTERC -> CIRCUIT_MODEL_MUX
|
||||||
|
* - DIRECT_INTERC -> CIRCUIT_MODEL_WIRE
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - COMPLETE_INTERC should not appear here!
|
||||||
|
* - We assume the interconnect type is the physical type
|
||||||
|
* after interconnect physical type annotation is done!
|
||||||
|
*******************************************************************/
|
||||||
|
e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_interconnect& pb_interc_type) {
|
||||||
|
/* A map from interconnect type to circuit model type */
|
||||||
|
std::map<e_interconnect, e_circuit_model_type> type_mapping;
|
||||||
|
type_mapping[MUX_INTERC] = CIRCUIT_MODEL_MUX;
|
||||||
|
type_mapping[DIRECT_INTERC] = CIRCUIT_MODEL_WIRE;
|
||||||
|
|
||||||
|
VTR_ASSERT((MUX_INTERC == pb_interc_type) || (DIRECT_INTERC == pb_interc_type));
|
||||||
|
|
||||||
|
return type_mapping.at(pb_interc_type);
|
||||||
|
}
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Include header files that are required by function declaration
|
* Include header files that are required by function declaration
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include "physical_types.h"
|
#include "physical_types.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Function declaration
|
* 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);
|
t_pb_type* find_mode_child_pb_type(t_mode* mode, const char* child_name);
|
||||||
|
|
||||||
|
std::vector<t_port*> pb_type_ports(t_pb_type* pb_type);
|
||||||
|
|
||||||
|
t_port* find_pb_type_port(t_pb_type* pb_type, const std::string& port_name);
|
||||||
|
|
||||||
|
t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
|
||||||
|
const std::vector<std::string>& target_pb_type_names,
|
||||||
|
const std::vector<std::string>& target_pb_mode_names);
|
||||||
|
|
||||||
|
std::vector<t_interconnect*> pb_mode_interconnects(t_mode* pb_mode);
|
||||||
|
|
||||||
|
t_interconnect* find_pb_mode_interconnect(t_mode* pb_mode, const char* interc_name);
|
||||||
|
|
||||||
|
e_interconnect pb_interconnect_physical_type(t_interconnect* pb_interc,
|
||||||
|
const size_t& num_inputs);
|
||||||
|
|
||||||
|
e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_interconnect& pb_interc_type);
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,8 +16,18 @@ VprPbTypeAnnotation::VprPbTypeAnnotation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Public mutators
|
* Public accessors
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
bool VprPbTypeAnnotation::is_physical_pb_type(t_pb_type* pb_type) const {
|
||||||
|
/* Ensure that the pb_type is in the list */
|
||||||
|
std::map<t_pb_type*, t_pb_type*>::const_iterator it = physical_pb_types_.find(pb_type);
|
||||||
|
if (it == physical_pb_types_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* A physical pb_type should be mapped to itself! Otherwise, it is an operating pb_type */
|
||||||
|
return pb_type == physical_pb_types_.at(pb_type);
|
||||||
|
}
|
||||||
|
|
||||||
t_mode* VprPbTypeAnnotation::physical_mode(t_pb_type* pb_type) const {
|
t_mode* VprPbTypeAnnotation::physical_mode(t_pb_type* pb_type) const {
|
||||||
/* Ensure that the pb_type is in the list */
|
/* Ensure that the pb_type is in the list */
|
||||||
std::map<t_pb_type*, t_mode*>::const_iterator it = physical_pb_modes_.find(pb_type);
|
std::map<t_pb_type*, t_mode*>::const_iterator it = physical_pb_modes_.find(pb_type);
|
||||||
|
@ -27,6 +37,64 @@ t_mode* VprPbTypeAnnotation::physical_mode(t_pb_type* pb_type) const {
|
||||||
return physical_pb_modes_.at(pb_type);
|
return physical_pb_modes_.at(pb_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_pb_type* VprPbTypeAnnotation::physical_pb_type(t_pb_type* pb_type) const {
|
||||||
|
/* Ensure that the pb_type is in the list */
|
||||||
|
std::map<t_pb_type*, t_pb_type*>::const_iterator it = physical_pb_types_.find(pb_type);
|
||||||
|
if (it == physical_pb_types_.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return physical_pb_types_.at(pb_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_port* VprPbTypeAnnotation::physical_pb_port(t_port* pb_port) const {
|
||||||
|
/* Ensure that the pb_type is in the list */
|
||||||
|
std::map<t_port*, t_port*>::const_iterator it = physical_pb_ports_.find(pb_port);
|
||||||
|
if (it == physical_pb_ports_.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return physical_pb_ports_.at(pb_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicPort VprPbTypeAnnotation::physical_pb_port_range(t_port* pb_port) const {
|
||||||
|
/* Ensure that the pb_type is in the list */
|
||||||
|
std::map<t_port*, BasicPort>::const_iterator it = physical_pb_port_ranges_.find(pb_port);
|
||||||
|
if (it == physical_pb_port_ranges_.end()) {
|
||||||
|
/* Return an invalid port. As such the port width will be 0, which is an invalid value */
|
||||||
|
return BasicPort();
|
||||||
|
}
|
||||||
|
return physical_pb_port_ranges_.at(pb_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
CircuitModelId VprPbTypeAnnotation::pb_type_circuit_model(t_pb_type* physical_pb_type) const {
|
||||||
|
/* Ensure that the pb_type is in the list */
|
||||||
|
std::map<t_pb_type*, CircuitModelId>::const_iterator it = pb_type_circuit_models_.find(physical_pb_type);
|
||||||
|
if (it == pb_type_circuit_models_.end()) {
|
||||||
|
/* Return an invalid circuit model id */
|
||||||
|
return CircuitModelId::INVALID();
|
||||||
|
}
|
||||||
|
return pb_type_circuit_models_.at(physical_pb_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
CircuitModelId VprPbTypeAnnotation::interconnect_circuit_model(t_interconnect* pb_interconnect) const {
|
||||||
|
/* Ensure that the pb_type is in the list */
|
||||||
|
std::map<t_interconnect*, CircuitModelId>::const_iterator it = interconnect_circuit_models_.find(pb_interconnect);
|
||||||
|
if (it == interconnect_circuit_models_.end()) {
|
||||||
|
/* Return an invalid circuit model id */
|
||||||
|
return CircuitModelId::INVALID();
|
||||||
|
}
|
||||||
|
return interconnect_circuit_models_.at(pb_interconnect);
|
||||||
|
}
|
||||||
|
|
||||||
|
e_interconnect VprPbTypeAnnotation::interconnect_physical_type(t_interconnect* pb_interconnect) const {
|
||||||
|
/* Ensure that the pb_type is in the list */
|
||||||
|
std::map<t_interconnect*, e_interconnect>::const_iterator it = interconnect_physical_types_.find(pb_interconnect);
|
||||||
|
if (it == interconnect_physical_types_.end()) {
|
||||||
|
/* Return an invalid circuit model id */
|
||||||
|
return NUM_INTERC_TYPES;
|
||||||
|
}
|
||||||
|
return interconnect_physical_types_.at(pb_interconnect);
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Public mutators
|
* 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;
|
physical_pb_modes_[pb_type] = physical_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VprPbTypeAnnotation::add_physical_pb_type(t_pb_type* operating_pb_type, t_pb_type* physical_pb_type) {
|
||||||
|
/* Warn any override attempt */
|
||||||
|
std::map<t_pb_type*, t_pb_type*>::const_iterator it = physical_pb_types_.find(operating_pb_type);
|
||||||
|
if (it != physical_pb_types_.end()) {
|
||||||
|
VTR_LOG_WARN("Override the annotation between operating pb_type '%s' and it physical pb_type '%s'!\n",
|
||||||
|
operating_pb_type->name, physical_pb_type->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
physical_pb_types_[operating_pb_type] = physical_pb_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VprPbTypeAnnotation::add_physical_pb_port(t_port* operating_pb_port, t_port* physical_pb_port) {
|
||||||
|
/* Warn any override attempt */
|
||||||
|
std::map<t_port*, t_port*>::const_iterator it = physical_pb_ports_.find(operating_pb_port);
|
||||||
|
if (it != physical_pb_ports_.end()) {
|
||||||
|
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port '%s'!\n",
|
||||||
|
operating_pb_port->name, physical_pb_port->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
physical_pb_ports_[operating_pb_port] = physical_pb_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VprPbTypeAnnotation::add_physical_pb_port_range(t_port* operating_pb_port, const BasicPort& port_range) {
|
||||||
|
/* The port range must satify the port width*/
|
||||||
|
VTR_ASSERT((size_t)operating_pb_port->num_pins == port_range.get_width());
|
||||||
|
|
||||||
|
/* Warn any override attempt */
|
||||||
|
std::map<t_port*, BasicPort>::const_iterator it = physical_pb_port_ranges_.find(operating_pb_port);
|
||||||
|
if (it != physical_pb_port_ranges_.end()) {
|
||||||
|
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port range '[%ld:%ld]'!\n",
|
||||||
|
operating_pb_port->name, port_range.get_lsb(), port_range.get_msb());
|
||||||
|
}
|
||||||
|
|
||||||
|
physical_pb_port_ranges_[operating_pb_port] = port_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VprPbTypeAnnotation::add_pb_type_circuit_model(t_pb_type* physical_pb_type, const CircuitModelId& circuit_model) {
|
||||||
|
/* Warn any override attempt */
|
||||||
|
std::map<t_pb_type*, CircuitModelId>::const_iterator it = pb_type_circuit_models_.find(physical_pb_type);
|
||||||
|
if (it != pb_type_circuit_models_.end()) {
|
||||||
|
VTR_LOG_WARN("Override the circuit model for physical pb_type '%s'!\n",
|
||||||
|
physical_pb_type->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pb_type_circuit_models_[physical_pb_type] = circuit_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VprPbTypeAnnotation::add_interconnect_circuit_model(t_interconnect* pb_interconnect, const CircuitModelId& circuit_model) {
|
||||||
|
/* Warn any override attempt */
|
||||||
|
std::map<t_interconnect*, CircuitModelId>::const_iterator it = interconnect_circuit_models_.find(pb_interconnect);
|
||||||
|
if (it != interconnect_circuit_models_.end()) {
|
||||||
|
VTR_LOG_WARN("Override the circuit model for interconnect '%s'!\n",
|
||||||
|
pb_interconnect->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
interconnect_circuit_models_[pb_interconnect] = circuit_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VprPbTypeAnnotation::add_interconnect_physical_type(t_interconnect* pb_interconnect,
|
||||||
|
const e_interconnect& physical_type) {
|
||||||
|
/* Warn any override attempt */
|
||||||
|
std::map<t_interconnect*, e_interconnect>::const_iterator it = interconnect_physical_types_.find(pb_interconnect);
|
||||||
|
if (it != interconnect_physical_types_.end()) {
|
||||||
|
VTR_LOG_WARN("Override the physical interconnect for interconnect '%s'!\n",
|
||||||
|
pb_interconnect->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
interconnect_physical_types_[pb_interconnect] = physical_type;
|
||||||
|
}
|
||||||
|
|
||||||
} /* End namespace openfpga*/
|
} /* End namespace openfpga*/
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "physical_types.h"
|
#include "physical_types.h"
|
||||||
|
|
||||||
/* Header from openfpgautil library */
|
/* Header from openfpgautil library */
|
||||||
|
#include "openfpga_port.h"
|
||||||
#include "circuit_library.h"
|
#include "circuit_library.h"
|
||||||
|
|
||||||
/* Begin namespace openfpga */
|
/* Begin namespace openfpga */
|
||||||
|
@ -28,14 +29,76 @@ class VprPbTypeAnnotation {
|
||||||
public: /* Constructor */
|
public: /* Constructor */
|
||||||
VprPbTypeAnnotation();
|
VprPbTypeAnnotation();
|
||||||
public: /* Public accessors */
|
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_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 */
|
public: /* Public mutators */
|
||||||
void add_pb_type_physical_mode(t_pb_type* pb_type, t_mode* physical_mode);
|
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 */
|
private: /* Internal data */
|
||||||
std::map<t_pb_type*, bool> is_physical_pb_types_;
|
/* Pair a regular pb_type to its physical pb_type */
|
||||||
std::map<t_pb_type*, t_pb_type*> physical_pb_types_;
|
std::map<t_pb_type*, t_pb_type*> physical_pb_types_;
|
||||||
|
|
||||||
|
/* Pair a physical mode for a pb_type
|
||||||
|
* Note:
|
||||||
|
* - the physical mode MUST be a child mode of the pb_type
|
||||||
|
* - the pb_type MUST be a physical pb_type itself
|
||||||
|
*/
|
||||||
std::map<t_pb_type*, t_mode*> physical_pb_modes_;
|
std::map<t_pb_type*, t_mode*> physical_pb_modes_;
|
||||||
|
|
||||||
|
/* Pair a physical pb_type to its circuit model
|
||||||
|
* Note:
|
||||||
|
* - the pb_type MUST be a physical pb_type itself
|
||||||
|
*/
|
||||||
std::map<t_pb_type*, CircuitModelId> pb_type_circuit_models_;
|
std::map<t_pb_type*, CircuitModelId> pb_type_circuit_models_;
|
||||||
|
|
||||||
|
/* Pair a interconnect of a physical pb_type to its circuit model
|
||||||
|
* Note:
|
||||||
|
* - the pb_type MUST be a physical pb_type itself
|
||||||
|
*/
|
||||||
|
std::map<t_interconnect*, CircuitModelId> interconnect_circuit_models_;
|
||||||
|
|
||||||
|
/* Physical type of interconnect
|
||||||
|
* Note:
|
||||||
|
* - only applicable to an interconnect belongs to physical mode
|
||||||
|
*/
|
||||||
|
std::map<t_interconnect*, e_interconnect> interconnect_physical_types_;
|
||||||
|
|
||||||
|
/* Pair a pb_type to its mode selection bits
|
||||||
|
* - if the pb_type is a physical pb_type, the mode bits are the default mode
|
||||||
|
* where the physical pb_type will operate when used
|
||||||
|
* - if the pb_type is an operating pb_type, the mode bits will be applied
|
||||||
|
* when the operating pb_type is used by packer
|
||||||
|
*/
|
||||||
|
std::map<t_pb_type*, std::vector<bool>> pb_type_mode_bits_;
|
||||||
|
|
||||||
|
/* Pair a pb_port to its physical pb_port
|
||||||
|
* Note:
|
||||||
|
* - the parent of physical pb_port MUST be a physical pb_type
|
||||||
|
*/
|
||||||
|
std::map<t_port*, t_port*> physical_pb_ports_;
|
||||||
|
|
||||||
|
/* Pair a pb_port to its LSB and MSB of a physical pb_port
|
||||||
|
* Note:
|
||||||
|
* - the LSB and MSB MUST be in range of the physical pb_port
|
||||||
|
*/
|
||||||
|
std::map<t_port*, BasicPort> physical_pb_port_ranges_;
|
||||||
|
|
||||||
|
/* Pair a pb_graph_node to a physical pb_graph_node
|
||||||
|
* Note:
|
||||||
|
* - the pb_type of physical pb_graph_node must be a physical pb_type
|
||||||
|
*/
|
||||||
|
std::map<t_pb_graph_node*, t_pb_graph_node*> physical_pb_graph_nodes_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* End namespace openfpga*/
|
} /* End namespace openfpga*/
|
||||||
|
|
|
@ -134,16 +134,16 @@
|
||||||
<port type="output" prefix="Q" size="1"/>
|
<port type="output" prefix="Q" size="1"/>
|
||||||
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0" />
|
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0" />
|
||||||
</circuit_model>
|
</circuit_model>
|
||||||
<circuit_model type="lut" name="lut5" prefix="lut5" dump_structural_verilog="true">
|
<circuit_model type="lut" name="lut6" prefix="lut6" dump_structural_verilog="true">
|
||||||
<design_technology type="cmos"/>
|
<design_technology type="cmos"/>
|
||||||
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
|
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
|
||||||
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
|
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
|
||||||
<pass_gate_logic circuit_model_name="TGATE"/>
|
<pass_gate_logic circuit_model_name="TGATE"/>
|
||||||
<port type="input" prefix="in" size="5"/>
|
<port type="input" prefix="in" size="6"/>
|
||||||
<port type="output" prefix="out" size="1"/>
|
<port type="output" prefix="out" size="1"/>
|
||||||
<port type="sram" prefix="sram" size="32"/>
|
<port type="sram" prefix="sram" size="64"/>
|
||||||
</circuit_model>
|
</circuit_model>
|
||||||
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
|
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
|
||||||
<circuit_model type="ccff" name="sc_dff_compact" prefix="scff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/ff.v">
|
<circuit_model type="ccff" name="sc_dff_compact" prefix="scff" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/ff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/ff.v">
|
||||||
|
|
|
@ -6,3 +6,6 @@ read_openfpga_arch -f ./test_openfpga_arch/k6_N10_40nm_openfpga.xml
|
||||||
|
|
||||||
# Annotate the OpenFPGA architecture to VPR data base
|
# Annotate the OpenFPGA architecture to VPR data base
|
||||||
link_openfpga_arch
|
link_openfpga_arch
|
||||||
|
|
||||||
|
# Finish and exit OpenFPGA
|
||||||
|
exit
|
||||||
|
|
Loading…
Reference in New Issue