add physical type annotation for interconnects and inference

This commit is contained in:
tangxifan 2020-01-28 21:59:10 -07:00
parent bb7fa2af77
commit 8a7a4dc48e
11 changed files with 423 additions and 3 deletions

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@
#include "vpr_pb_type_annotation.h"
#include "pb_type_utils.h"
#include "annotate_pb_graph.h"
#include "annotate_pb_types.h"
/* begin namespace openfpga */
@ -843,6 +844,92 @@ void link_vpr_pb_interconnect_to_circuit_model_explicit_annotation(const DeviceC
}
}
/********************************************************************
* 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
@ -862,6 +949,13 @@ void annotate_pb_types(const DeviceContext& vpr_device_ctx,
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);
@ -876,10 +970,13 @@ void annotate_pb_types(const DeviceContext& vpr_device_ctx,
* - 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 */

View File

@ -10,6 +10,7 @@
#include "vpr_pb_type_annotation.h"
#include "pb_type_utils.h"
#include "annotate_pb_types.h"
#include "annotate_pb_graph.h"
#include "openfpga_link_arch.h"
/* Include global variables of VPR */

View File

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

View File

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

View File

@ -1,7 +1,9 @@
/********************************************************************
* This file includes most utilized functions for the pb_type
* and pb_graph_node data structure in the OpenFPGA context
* This file includes most utilized functions for the t_pb_type,
* t_mode and t_port data structure in the OpenFPGA context
*******************************************************************/
#include <map>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
@ -138,6 +140,18 @@ t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
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.
@ -154,4 +168,64 @@ t_interconnect* find_pb_mode_interconnect(t_mode* pb_mode, const char* interc_na
return nullptr;
}
/********************************************************************
* This function will automatically infer the actual type of an interconnect
* that will be used to implement the physical design:
* - MUX_INTERC -> MUX_INTERC
* - DIRECT_INTERC -> DIRECT_INTERC
* - COMPLETE_INTERC (single input) -> DIRECT_INTERC
* - COMPLETE_INTERC (multiple input pins) -> MUX_INTERC
*******************************************************************/
e_interconnect pb_interconnect_physical_type(t_interconnect* pb_interc,
const size_t& num_inputs) {
/* Check */
VTR_ASSERT(nullptr != pb_interc);
/* Initialize the interconnection type that will be implemented in SPICE netlist*/
switch (pb_interc->type) {
case DIRECT_INTERC:
return DIRECT_INTERC;
break;
case COMPLETE_INTERC:
if (1 == num_inputs) {
return DIRECT_INTERC;
} else {
VTR_ASSERT(1 < num_inputs);
return MUX_INTERC;
}
break;
case MUX_INTERC:
return MUX_INTERC;
break;
default:
VTR_LOG_ERROR("Invalid type for interconnection '%s'!\n",
pb_interc->name);
exit(1);
}
return NUM_INTERC_TYPES;
}
/********************************************************************
* This function will automatically infer the actual type of an interconnect
* that will be used to implement the physical design:
* - MUX_INTERC -> CIRCUIT_MODEL_MUX
* - DIRECT_INTERC -> CIRCUIT_MODEL_WIRE
*
* Note:
* - COMPLETE_INTERC should not appear here!
* - We assume the interconnect type is the physical type
* after interconnect physical type annotation is done!
*******************************************************************/
e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_interconnect& pb_interc_type) {
/* A map from interconnect type to circuit model type */
std::map<e_interconnect, e_circuit_model_type> type_mapping;
type_mapping[MUX_INTERC] = CIRCUIT_MODEL_MUX;
type_mapping[DIRECT_INTERC] = CIRCUIT_MODEL_WIRE;
VTR_ASSERT((MUX_INTERC == pb_interc_type) || (DIRECT_INTERC == pb_interc_type));
return type_mapping.at(pb_interc_type);
}
} /* end namespace openfpga */

View File

@ -7,6 +7,7 @@
#include <string>
#include <vector>
#include "physical_types.h"
#include "circuit_library.h"
/********************************************************************
* Function declaration
@ -31,8 +32,15 @@ t_pb_type* try_find_pb_type_with_given_path(t_pb_type* top_pb_type,
const std::vector<std::string>& target_pb_type_names,
const std::vector<std::string>& target_pb_mode_names);
std::vector<t_interconnect*> pb_mode_interconnects(t_mode* pb_mode);
t_interconnect* find_pb_mode_interconnect(t_mode* pb_mode, const char* interc_name);
e_interconnect pb_interconnect_physical_type(t_interconnect* pb_interc,
const size_t& num_inputs);
e_circuit_model_type pb_interconnect_require_circuit_model_type(const e_interconnect& pb_interc_type);
} /* end namespace openfpga */
#endif

View File

@ -85,6 +85,16 @@ CircuitModelId VprPbTypeAnnotation::interconnect_circuit_model(t_interconnect* p
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
***********************************************************************/
@ -157,4 +167,16 @@ void VprPbTypeAnnotation::add_interconnect_circuit_model(t_interconnect* pb_inte
interconnect_circuit_models_[pb_interconnect] = circuit_model;
}
void VprPbTypeAnnotation::add_interconnect_physical_type(t_interconnect* pb_interconnect,
const e_interconnect& physical_type) {
/* Warn any override attempt */
std::map<t_interconnect*, e_interconnect>::const_iterator it = interconnect_physical_types_.find(pb_interconnect);
if (it != interconnect_physical_types_.end()) {
VTR_LOG_WARN("Override the physical interconnect for interconnect '%s'!\n",
pb_interconnect->name);
}
interconnect_physical_types_[pb_interconnect] = physical_type;
}
} /* End namespace openfpga*/

View File

@ -36,6 +36,7 @@ class VprPbTypeAnnotation {
BasicPort physical_pb_port_range(t_port* pb_port) const;
CircuitModelId pb_type_circuit_model(t_pb_type* physical_pb_type) const;
CircuitModelId interconnect_circuit_model(t_interconnect* pb_interconnect) const;
e_interconnect interconnect_physical_type(t_interconnect* pb_interconnect) const;
public: /* Public mutators */
void add_pb_type_physical_mode(t_pb_type* pb_type, t_mode* physical_mode);
void add_physical_pb_type(t_pb_type* operating_pb_type, t_pb_type* physical_pb_type);
@ -43,6 +44,7 @@ class VprPbTypeAnnotation {
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 */
/* Pair a regular pb_type to its physical pb_type */
std::map<t_pb_type*, t_pb_type*> physical_pb_types_;
@ -66,6 +68,12 @@ class VprPbTypeAnnotation {
*/
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