Merge branch 'refactoring' into dev
This commit is contained in:
commit
b63ba31dcb
|
@ -0,0 +1,434 @@
|
|||
/********************************************************************
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively walk through all the pb_graph nodes
|
||||
* starting from a top node.
|
||||
* It aims to give an unique index to each pb_graph node
|
||||
*
|
||||
* Therefore, the sequence in visiting the nodes is critical
|
||||
* Here, we will follow the strategy where primitive nodes are visited first
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_build_vpr_primitive_pb_graph_node_unique_index(t_pb_graph_node* pb_graph_node,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
/* Go recursive first until we touch the primitive node */
|
||||
if (false == is_primitive_pb_type(pb_graph_node->pb_type)) {
|
||||
for (int imode = 0; imode < pb_graph_node->pb_type->num_modes; ++imode) {
|
||||
for (int ipb = 0; ipb < pb_graph_node->pb_type->modes[imode].num_pb_type_children; ++ipb) {
|
||||
/* Each child may exist multiple times in the hierarchy*/
|
||||
for (int jpb = 0; jpb < pb_graph_node->pb_type->modes[imode].pb_type_children[ipb].num_pb; ++jpb) {
|
||||
rec_build_vpr_primitive_pb_graph_node_unique_index(&(pb_graph_node->child_pb_graph_nodes[imode][ipb][jpb]),
|
||||
vpr_pb_type_annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Give a unique index to the pb_graph_node */
|
||||
vpr_pb_type_annotation.add_pb_graph_node_unique_index(pb_graph_node);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function aims to assign an unique index to each
|
||||
* primitive pb_graph_node by following a recursive way in walking
|
||||
* through the pb_graph
|
||||
*
|
||||
* Note:
|
||||
* - The unique index is different from the placement_index in VPR's
|
||||
* pb_graph_node data structure. The placement index is only unique
|
||||
* for a node under its parent node. If the parent node is duplicated
|
||||
* across the graph, the placement index is not unique.
|
||||
* For example, a CLB contains 10 LEs and each of LE contains 2 LUTs
|
||||
* Inside each LE, the placement index of the LUTs are 0 and 1 respectively.
|
||||
* But these indices are not unique in the graph, as there are 20 LUTs in total
|
||||
*******************************************************************/
|
||||
static
|
||||
void annotate_primitive_pb_graph_node_unique_index(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_primitive_pb_graph_node_unique_index(lb_type.pb_graph_head, vpr_pb_type_annotation);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Evaluate if the two pb_graph pins are matched by
|
||||
* - pb_type port annotation
|
||||
* - LSB/MSB and pin offset
|
||||
*******************************************************************/
|
||||
static
|
||||
bool try_match_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin,
|
||||
t_pb_graph_pin* physical_pb_graph_pin,
|
||||
const VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
/* If the parent ports of the two pins are not paired, fail */
|
||||
if (physical_pb_graph_pin->port != vpr_pb_type_annotation.physical_pb_port(operating_pb_graph_pin->port)) {
|
||||
return false;
|
||||
}
|
||||
/* Check the pin number of physical pb_graph_pin matches the pin number of
|
||||
* operating pb_graph_pin plus a rotation offset
|
||||
* operating port physical port
|
||||
* LSB port_range.lsb() pin_number pin_number MSB
|
||||
* | | |
|
||||
* Operating port | | +------ |
|
||||
* | |<----offset--->|
|
||||
* Physical port | + + +
|
||||
*
|
||||
* Note:
|
||||
* - accumulated offset is NOT the pin rotate offset specified by users
|
||||
* It is an aggregation of the offset during pin pairing
|
||||
* Each time, we manage to pair two pins, the accumulated offset will be incremented
|
||||
* by the pin rotate offset value
|
||||
* The accumulated offset will be reset to 0 when it exceeds the msb() of the physical port
|
||||
*/
|
||||
int acc_offset = vpr_pb_type_annotation.physical_pb_pin_offset(operating_pb_graph_pin->port);
|
||||
const BasicPort& physical_port_range = vpr_pb_type_annotation.physical_pb_port_range(operating_pb_graph_pin->port);
|
||||
if (physical_pb_graph_pin->pin_number != operating_pb_graph_pin->pin_number
|
||||
+ (int)physical_port_range.get_lsb()
|
||||
+ acc_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Reach here, it means all the requirements have been met */
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Bind a pb_graph_pin from an operating pb_graph_node to
|
||||
* a pb_graph_pin from a physical pb_graph_node
|
||||
* - the name matching rules are already defined in the vpr_pb_type_annotation
|
||||
*******************************************************************/
|
||||
static
|
||||
void annotate_physical_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin,
|
||||
t_pb_graph_node* physical_pb_graph_node,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
/* Iterate over every port and pin of the operating pb_graph_node
|
||||
* and find the physical pins
|
||||
*/
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_input_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||
if (false == try_match_pb_graph_pin(operating_pb_graph_pin,
|
||||
&(physical_pb_graph_node->input_pins[iport][ipin]),
|
||||
vpr_pb_type_annotation)) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means the pins are matched by the annotation requirements
|
||||
* We can pair the pin and return
|
||||
*/
|
||||
vpr_pb_type_annotation.add_physical_pb_graph_pin(operating_pb_graph_pin, &(physical_pb_graph_node->input_pins[iport][ipin]));
|
||||
VTR_LOG("Bind a pb_graph_node '%s[%d]' pin '%s[%d]' to a pb_graph_node '%s[%d]' pin '%s[%d]'!\n",
|
||||
operating_pb_graph_pin->parent_node->pb_type->name,
|
||||
operating_pb_graph_pin->parent_node->placement_index,
|
||||
operating_pb_graph_pin->port->name,
|
||||
operating_pb_graph_pin->pin_number,
|
||||
physical_pb_graph_node->pb_type->name,
|
||||
physical_pb_graph_node->placement_index,
|
||||
physical_pb_graph_node->input_pins[iport][ipin].port->name,
|
||||
physical_pb_graph_node->input_pins[iport][ipin].pin_number);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_output_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) {
|
||||
if (false == try_match_pb_graph_pin(operating_pb_graph_pin,
|
||||
&(physical_pb_graph_node->output_pins[iport][ipin]),
|
||||
vpr_pb_type_annotation)) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means the pins are matched by the annotation requirements
|
||||
* We can pair the pin and return
|
||||
*/
|
||||
vpr_pb_type_annotation.add_physical_pb_graph_pin(operating_pb_graph_pin, &(physical_pb_graph_node->output_pins[iport][ipin]));
|
||||
VTR_LOG("Bind a pb_graph_node '%s[%d]' pin '%s[%d]' to a pb_graph_node '%s[%d]' pin '%s[%d]'!\n",
|
||||
operating_pb_graph_pin->parent_node->pb_type->name,
|
||||
operating_pb_graph_pin->parent_node->placement_index,
|
||||
operating_pb_graph_pin->port->name,
|
||||
operating_pb_graph_pin->pin_number,
|
||||
physical_pb_graph_node->pb_type->name,
|
||||
physical_pb_graph_node->placement_index,
|
||||
physical_pb_graph_node->output_pins[iport][ipin].port->name,
|
||||
physical_pb_graph_node->output_pins[iport][ipin].pin_number);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int iport = 0; iport < physical_pb_graph_node->num_clock_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) {
|
||||
if (false == try_match_pb_graph_pin(operating_pb_graph_pin,
|
||||
&(physical_pb_graph_node->clock_pins[iport][ipin]),
|
||||
vpr_pb_type_annotation)) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means the pins are matched by the annotation requirements
|
||||
* We can pair the pin and return
|
||||
*/
|
||||
vpr_pb_type_annotation.add_physical_pb_graph_pin(operating_pb_graph_pin, &(physical_pb_graph_node->clock_pins[iport][ipin]));
|
||||
VTR_LOG("Bind a pb_graph_node '%s[%d]' pin '%s[%d]' to a pb_graph_node '%s[%d]' pin '%s[%d]'!\n",
|
||||
operating_pb_graph_pin->parent_node->pb_type->name,
|
||||
operating_pb_graph_pin->parent_node->placement_index,
|
||||
operating_pb_graph_pin->port->name,
|
||||
operating_pb_graph_pin->pin_number,
|
||||
physical_pb_graph_node->pb_type->name,
|
||||
physical_pb_graph_node->placement_index,
|
||||
physical_pb_graph_node->clock_pins[iport][ipin].port->name,
|
||||
physical_pb_graph_node->clock_pins[iport][ipin].pin_number);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we reach here, it means that pin pairing fails, error out! */
|
||||
VTR_LOG_ERROR("Fail to match a physical pin for '%s' from pb_graph_node '%s'!\n",
|
||||
operating_pb_graph_pin->port->name,
|
||||
physical_pb_graph_node->hierarchical_type_name().c_str());
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will try bind each pin of the operating pb_graph_node
|
||||
* to a pin of the physical pb_graph_node by following the annotation
|
||||
* available in vpr_pb_type_annotation
|
||||
* It will add the pin bindings to the vpr_pb_type_annotation
|
||||
*******************************************************************/
|
||||
static
|
||||
void annotate_physical_pb_graph_node_pins(t_pb_graph_node* operating_pb_graph_node,
|
||||
t_pb_graph_node* physical_pb_graph_node,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
/* Iterate over every port and pin of the operating pb_graph_node
|
||||
* and find the physical pins
|
||||
*/
|
||||
for (int iport = 0; iport < operating_pb_graph_node->num_input_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < operating_pb_graph_node->num_input_pins[iport]; ++ipin) {
|
||||
annotate_physical_pb_graph_pin(&(operating_pb_graph_node->input_pins[iport][ipin]),
|
||||
physical_pb_graph_node, vpr_pb_type_annotation);
|
||||
}
|
||||
}
|
||||
|
||||
for (int iport = 0; iport < operating_pb_graph_node->num_output_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < operating_pb_graph_node->num_output_pins[iport]; ++ipin) {
|
||||
annotate_physical_pb_graph_pin(&(operating_pb_graph_node->output_pins[iport][ipin]),
|
||||
physical_pb_graph_node, vpr_pb_type_annotation);
|
||||
}
|
||||
}
|
||||
|
||||
for (int iport = 0; iport < operating_pb_graph_node->num_clock_ports; ++iport) {
|
||||
for (int ipin = 0; ipin < operating_pb_graph_node->num_clock_pins[iport]; ++ipin) {
|
||||
annotate_physical_pb_graph_pin(&(operating_pb_graph_node->clock_pins[iport][ipin]),
|
||||
physical_pb_graph_node, vpr_pb_type_annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* This function will recursively walk through all the pb_graph nodes
|
||||
* starting from a top node.
|
||||
* It aims to give an unique index to each pb_graph node
|
||||
*
|
||||
* Therefore, the sequence in visiting the nodes is critical
|
||||
* Here, we will follow the strategy where primitive nodes are visited first
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_build_vpr_physical_pb_graph_node_annotation(t_pb_graph_node* pb_graph_node,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
/* Go recursive first until we touch the primitive node */
|
||||
if (false == is_primitive_pb_type(pb_graph_node->pb_type)) {
|
||||
for (int imode = 0; imode < pb_graph_node->pb_type->num_modes; ++imode) {
|
||||
for (int ipb = 0; ipb < pb_graph_node->pb_type->modes[imode].num_pb_type_children; ++ipb) {
|
||||
/* Each child may exist multiple times in the hierarchy*/
|
||||
for (int jpb = 0; jpb < pb_graph_node->pb_type->modes[imode].pb_type_children[ipb].num_pb; ++jpb) {
|
||||
rec_build_vpr_physical_pb_graph_node_annotation(&(pb_graph_node->child_pb_graph_nodes[imode][ipb][jpb]),
|
||||
vpr_pb_type_annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* To bind operating pb_graph_node to their physical pb_graph_node:
|
||||
* - Get the physical pb_type that this type of pb_graph_node should be mapped to
|
||||
* - Calculate the unique index of physical pb_graph_node to which
|
||||
* this pb_graph_node should be binded
|
||||
* - Find the physical pb_graph_node with the given index
|
||||
* To bind pins from operating pb_graph_node to their physical pb_graph_node pins
|
||||
*/
|
||||
t_pb_type* physical_pb_type = vpr_pb_type_annotation.physical_pb_type(pb_graph_node->pb_type);
|
||||
VTR_ASSERT(nullptr != physical_pb_type);
|
||||
|
||||
/* Index inference:
|
||||
* physical_pb_graph_node_unique_index = operating_pb_graph_node_unique_index * factor + offset
|
||||
* where factor and offset are provided by users
|
||||
*/
|
||||
PbGraphNodeId physical_pb_graph_node_id = PbGraphNodeId(
|
||||
vpr_pb_type_annotation.physical_pb_type_index_factor(pb_graph_node->pb_type)
|
||||
* (size_t)vpr_pb_type_annotation.pb_graph_node_unique_index(pb_graph_node)
|
||||
+ vpr_pb_type_annotation.physical_pb_type_index_offset(pb_graph_node->pb_type)
|
||||
);
|
||||
t_pb_graph_node* physical_pb_graph_node = vpr_pb_type_annotation.pb_graph_node(pb_graph_node->pb_type, physical_pb_graph_node_id);
|
||||
VTR_ASSERT(nullptr != physical_pb_graph_node);
|
||||
vpr_pb_type_annotation.add_physical_pb_graph_node(pb_graph_node, physical_pb_graph_node);
|
||||
|
||||
VTR_LOG("Bind operating pb_graph_node '%s' to physical pb_graph_node '%s'\n",
|
||||
pb_graph_node->hierarchical_type_name().c_str(),
|
||||
physical_pb_graph_node->hierarchical_type_name().c_str());
|
||||
|
||||
/* Try to bind each pins under this pb_graph_node to physical_pb_graph_node */
|
||||
annotate_physical_pb_graph_node_pins(pb_graph_node, physical_pb_graph_node, vpr_pb_type_annotation);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find the physical pb_graph_node for each primitive pb_graph_node
|
||||
* - Bind operating pb_graph_node to their physical pb_graph_node
|
||||
* - Bind pins from operating pb_graph_node to their physical pb_graph_node pins
|
||||
*******************************************************************/
|
||||
static
|
||||
void annotate_physical_pb_graph_node(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_physical_pb_graph_node_annotation(lb_type.pb_graph_head, vpr_pb_type_annotation);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Top-level function to annotate all the pb_graph nodes and pins
|
||||
* - Give unique index to each primitive node in the same type
|
||||
* - Bind operating pb_graph_node to their physical pb_graph_node
|
||||
* - Bind pins from operating pb_graph_node to their physical pb_graph_node pins
|
||||
*******************************************************************/
|
||||
void annotate_pb_graph(const DeviceContext& vpr_device_ctx,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation) {
|
||||
|
||||
VTR_LOG("Assigning unique indices for primitive pb_graph nodes...");
|
||||
annotate_primitive_pb_graph_node_unique_index(vpr_device_ctx, vpr_pb_type_annotation);
|
||||
VTR_LOG("Done\n");
|
||||
|
||||
VTR_LOG("Binding operating pb_graph nodes/pins to physical pb_graph nodes/pins...\n");
|
||||
annotate_physical_pb_graph_node(vpr_device_ctx, vpr_pb_type_annotation);
|
||||
VTR_LOG("Done\n");
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
@ -18,6 +18,9 @@ namespace openfpga {
|
|||
void annotate_pb_graph_interconnect_physical_type(const DeviceContext& vpr_device_ctx,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation);
|
||||
|
||||
void annotate_pb_graph(const DeviceContext& vpr_device_ctx,
|
||||
VprPbTypeAnnotation& vpr_pb_type_annotation);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -223,13 +223,24 @@ bool pair_operating_and_physical_pb_types(t_pb_type* operating_pb_type,
|
|||
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 */
|
||||
/* Now, port mapping should succeed, we update the vpr_pb_type_annotation
|
||||
* - port binding
|
||||
* - port range
|
||||
* - port pin rotate offset
|
||||
*/
|
||||
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);
|
||||
vpr_pb_type_annotation.add_physical_pb_pin_rotate_offset(operating_pb_port, pb_type_annotation.physical_pin_rotate_offset(std::string(operating_pb_port->name)));
|
||||
}
|
||||
|
||||
/* Now, pb_type mapping should succeed, we update the vpr_pb_type_annotation */
|
||||
/* Now, pb_type mapping should succeed, we update the vpr_pb_type_annotation
|
||||
* - pb_type binding
|
||||
* - physical_pb_type_index_factor
|
||||
* - physical_pb_type_index_offset
|
||||
*/
|
||||
vpr_pb_type_annotation.add_physical_pb_type(operating_pb_type, physical_pb_type);
|
||||
vpr_pb_type_annotation.add_physical_pb_type_index_factor(operating_pb_type, pb_type_annotation.physical_pb_type_index_factor());
|
||||
vpr_pb_type_annotation.add_physical_pb_type_index_offset(operating_pb_type, pb_type_annotation.physical_pb_type_index_offset());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -987,7 +998,12 @@ void annotate_pb_types(const DeviceContext& vpr_device_ctx,
|
|||
vpr_pb_type_annotation);
|
||||
VTR_LOG("Done\n");
|
||||
|
||||
/* Annotate physical pb_types to operating pb_type in the VPR pb_type graph */
|
||||
/* Annotate physical pb_types to operating pb_type in the VPR pb_type graph
|
||||
* This function will also annotate
|
||||
* - pb_type_index_factor
|
||||
* - pb_type_index_offset
|
||||
* - physical_pin_rotate_offset
|
||||
*/
|
||||
VTR_LOG("\n");
|
||||
VTR_LOG("Building annotation between operating and physical pb_types...\n");
|
||||
build_vpr_physical_pb_type_explicit_annotation(vpr_device_ctx, openfpga_arch,
|
|
@ -1,6 +1,8 @@
|
|||
/************************************************************************
|
||||
* Member functions for class VprPbTypeAnnotation
|
||||
***********************************************************************/
|
||||
#include <algorithm>
|
||||
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "vpr_pb_type_annotation.h"
|
||||
|
@ -115,6 +117,104 @@ std::vector<size_t> VprPbTypeAnnotation::pb_type_mode_bits(t_pb_type* pb_type) c
|
|||
return pb_type_mode_bits_.at(pb_type);
|
||||
}
|
||||
|
||||
PbGraphNodeId VprPbTypeAnnotation::pb_graph_node_unique_index(t_pb_graph_node* pb_graph_node) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_pb_type*, std::vector<t_pb_graph_node*>>::const_iterator it = pb_graph_node_unique_index_.find(pb_graph_node->pb_type);
|
||||
if (it == pb_graph_node_unique_index_.end()) {
|
||||
/* Invalid pb_type, return a null pointer */
|
||||
return PbGraphNodeId::INVALID();
|
||||
}
|
||||
|
||||
/* Try to find the pb_graph_node in the vector */
|
||||
std::vector<t_pb_graph_node*>::const_iterator it_node = std::find(pb_graph_node_unique_index_.at(pb_graph_node->pb_type).begin(),
|
||||
pb_graph_node_unique_index_.at(pb_graph_node->pb_type).end(),
|
||||
pb_graph_node);
|
||||
/* If it exists, return the index
|
||||
* Otherwise, return an invalid id
|
||||
*/
|
||||
if (it_node == pb_graph_node_unique_index_.at(pb_graph_node->pb_type).end()) {
|
||||
return PbGraphNodeId::INVALID();
|
||||
}
|
||||
return PbGraphNodeId(it_node - pb_graph_node_unique_index_.at(pb_graph_node->pb_type).begin());
|
||||
}
|
||||
|
||||
t_pb_graph_node* VprPbTypeAnnotation::pb_graph_node(t_pb_type* pb_type, const PbGraphNodeId& unique_index) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_pb_type*, std::vector<t_pb_graph_node*>>::const_iterator it = pb_graph_node_unique_index_.find(pb_type);
|
||||
if (it == pb_graph_node_unique_index_.end()) {
|
||||
/* Invalid pb_type, return a null pointer */
|
||||
return nullptr;
|
||||
}
|
||||
/* Check if the unique index is in the range:
|
||||
* - Out of range: return a null pointer
|
||||
* - In range: return the pointer
|
||||
*/
|
||||
if ((size_t)unique_index > pb_graph_node_unique_index_.at(pb_type).size() - 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pb_graph_node_unique_index_.at(pb_type)[size_t(unique_index)];
|
||||
}
|
||||
|
||||
t_pb_graph_node* VprPbTypeAnnotation::physical_pb_graph_node(t_pb_graph_node* pb_graph_node) const {
|
||||
/* Ensure that the pb_graph_node is in the list */
|
||||
std::map<t_pb_graph_node*, t_pb_graph_node*>::const_iterator it = physical_pb_graph_nodes_.find(pb_graph_node);
|
||||
if (it == physical_pb_graph_nodes_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return physical_pb_graph_nodes_.at(pb_graph_node);
|
||||
}
|
||||
|
||||
int VprPbTypeAnnotation::physical_pb_type_index_factor(t_pb_type* pb_type) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_pb_type*, int>::const_iterator it = physical_pb_type_index_factors_.find(pb_type);
|
||||
if (it == physical_pb_type_index_factors_.end()) {
|
||||
/* Default value is 1 */
|
||||
return 1;
|
||||
}
|
||||
return physical_pb_type_index_factors_.at(pb_type);
|
||||
}
|
||||
|
||||
int VprPbTypeAnnotation::physical_pb_type_index_offset(t_pb_type* pb_type) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_pb_type*, int>::const_iterator it = physical_pb_type_index_offsets_.find(pb_type);
|
||||
if (it == physical_pb_type_index_offsets_.end()) {
|
||||
/* Default value is 0 */
|
||||
return 0;
|
||||
}
|
||||
return physical_pb_type_index_offsets_.at(pb_type);
|
||||
}
|
||||
|
||||
int VprPbTypeAnnotation::physical_pb_pin_rotate_offset(t_port* pb_port) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_port*, int>::const_iterator it = physical_pb_pin_rotate_offsets_.find(pb_port);
|
||||
if (it == physical_pb_pin_rotate_offsets_.end()) {
|
||||
/* Default value is 0 */
|
||||
return 0;
|
||||
}
|
||||
return physical_pb_pin_rotate_offsets_.at(pb_port);
|
||||
}
|
||||
|
||||
int VprPbTypeAnnotation::physical_pb_pin_offset(t_port* pb_port) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_port*, int>::const_iterator it = physical_pb_pin_offsets_.find(pb_port);
|
||||
if (it == physical_pb_pin_offsets_.end()) {
|
||||
/* Default value is 0 */
|
||||
return 0;
|
||||
}
|
||||
return physical_pb_pin_offsets_.at(pb_port);
|
||||
}
|
||||
|
||||
|
||||
t_pb_graph_pin* VprPbTypeAnnotation::physical_pb_graph_pin(t_pb_graph_pin* pb_graph_pin) const {
|
||||
/* Ensure that the pb_type is in the list */
|
||||
std::map<t_pb_graph_pin*, t_pb_graph_pin*>::const_iterator it = physical_pb_graph_pins_.find(pb_graph_pin);
|
||||
if (it == physical_pb_graph_pins_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return physical_pb_graph_pins_.at(pb_graph_pin);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public mutators
|
||||
***********************************************************************/
|
||||
|
@ -221,4 +321,95 @@ void VprPbTypeAnnotation::add_pb_type_mode_bits(t_pb_type* pb_type, const std::v
|
|||
pb_type_mode_bits_[pb_type] = mode_bits;
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_pb_graph_node_unique_index(t_pb_graph_node* pb_graph_node) {
|
||||
pb_graph_node_unique_index_[pb_graph_node->pb_type].push_back(pb_graph_node);
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_physical_pb_graph_node(t_pb_graph_node* operating_pb_graph_node,
|
||||
t_pb_graph_node* physical_pb_graph_node) {
|
||||
/* Warn any override attempt */
|
||||
std::map<t_pb_graph_node*, t_pb_graph_node*>::const_iterator it = physical_pb_graph_nodes_.find(operating_pb_graph_node);
|
||||
if (it != physical_pb_graph_nodes_.end()) {
|
||||
VTR_LOG_WARN("Override the annotation between operating pb_graph_node '%s[%d]' and it physical pb_graph_node '%s[%d]'!\n",
|
||||
operating_pb_graph_node->pb_type->name,
|
||||
operating_pb_graph_node->placement_index,
|
||||
physical_pb_graph_node->pb_type->name,
|
||||
physical_pb_graph_node->placement_index);
|
||||
}
|
||||
|
||||
physical_pb_graph_nodes_[operating_pb_graph_node] = physical_pb_graph_node;
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_physical_pb_type_index_factor(t_pb_type* pb_type, const int& factor) {
|
||||
/* Warn any override attempt */
|
||||
std::map<t_pb_type*, int>::const_iterator it = physical_pb_type_index_factors_.find(pb_type);
|
||||
if (it != physical_pb_type_index_factors_.end()) {
|
||||
VTR_LOG_WARN("Override the annotation between operating pb_type '%s' and it physical pb_type index factor '%d'!\n",
|
||||
pb_type->name, factor);
|
||||
}
|
||||
|
||||
physical_pb_type_index_factors_[pb_type] = factor;
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_physical_pb_type_index_offset(t_pb_type* pb_type, const int& offset) {
|
||||
/* Warn any override attempt */
|
||||
std::map<t_pb_type*, int>::const_iterator it = physical_pb_type_index_offsets_.find(pb_type);
|
||||
if (it != physical_pb_type_index_offsets_.end()) {
|
||||
VTR_LOG_WARN("Override the annotation between operating pb_type '%s' and it physical pb_type index offset '%d'!\n",
|
||||
pb_type->name, offset);
|
||||
}
|
||||
|
||||
physical_pb_type_index_offsets_[pb_type] = offset;
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_physical_pb_pin_rotate_offset(t_port* pb_port, const int& offset) {
|
||||
/* Warn any override attempt */
|
||||
std::map<t_port*, int>::const_iterator it = physical_pb_pin_rotate_offsets_.find(pb_port);
|
||||
if (it != physical_pb_pin_rotate_offsets_.end()) {
|
||||
VTR_LOG_WARN("Override the annotation between operating pb_port '%s' and it physical pb_port pin rotate offset '%d'!\n",
|
||||
pb_port->name, offset);
|
||||
}
|
||||
|
||||
physical_pb_pin_rotate_offsets_[pb_port] = offset;
|
||||
/* We initialize the accumulated offset to 0 */
|
||||
physical_pb_pin_offsets_[pb_port] = 0;
|
||||
}
|
||||
|
||||
void VprPbTypeAnnotation::add_physical_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin,
|
||||
t_pb_graph_pin* physical_pb_graph_pin) {
|
||||
/* Warn any override attempt */
|
||||
std::map<t_pb_graph_pin*, t_pb_graph_pin*>::const_iterator it = physical_pb_graph_pins_.find(operating_pb_graph_pin);
|
||||
if (it != physical_pb_graph_pins_.end()) {
|
||||
VTR_LOG_WARN("Override the annotation between operating pb_graph_pin '%s' and it physical pb_graph_pin '%s'!\n",
|
||||
operating_pb_graph_pin->port->name, physical_pb_graph_pin->port->name);
|
||||
}
|
||||
|
||||
physical_pb_graph_pins_[operating_pb_graph_pin] = physical_pb_graph_pin;
|
||||
|
||||
/* Update the accumulated offsets for the operating port
|
||||
* Each time we pair two pins, we update the offset by the pin rotate offset
|
||||
* When the accumulated offset exceeds the MSB of the port range of physical port
|
||||
* we reset it to 0
|
||||
* operating port physical port
|
||||
* LSB port_range.lsb() pin_number pin_number MSB
|
||||
* | | |
|
||||
* Operating port | | +------ |
|
||||
* | |<----offset--->|
|
||||
* Physical port | + + +
|
||||
*
|
||||
*/
|
||||
if (0 == physical_pb_pin_rotate_offset(operating_pb_graph_pin->port)) {
|
||||
return;
|
||||
}
|
||||
|
||||
physical_pb_pin_offsets_[operating_pb_graph_pin->port] += physical_pb_pin_rotate_offset(operating_pb_graph_pin->port);
|
||||
|
||||
if (physical_pb_port_range(operating_pb_graph_pin->port).get_msb()
|
||||
< operating_pb_graph_pin->pin_number
|
||||
+ physical_pb_port_range(operating_pb_graph_pin->port).get_lsb()
|
||||
+ physical_pb_pin_offset(operating_pb_graph_pin->port)) {
|
||||
physical_pb_pin_offsets_[operating_pb_graph_pin->port] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} /* End namespace openfpga*/
|
|
@ -6,6 +6,9 @@
|
|||
*******************************************************************/
|
||||
#include <map>
|
||||
|
||||
/* Header from vtrutil library */
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
/* Header from archfpga library */
|
||||
#include "physical_types.h"
|
||||
|
||||
|
@ -16,6 +19,11 @@
|
|||
/* Begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/* Unique index for pb_graph node */
|
||||
struct pb_graph_node_id_tag;
|
||||
|
||||
typedef vtr::StrongId<pb_graph_node_id_tag> PbGraphNodeId;
|
||||
|
||||
/********************************************************************
|
||||
* This is the critical data structure to link the pb_type in VPR
|
||||
* to openfpga annotations
|
||||
|
@ -39,6 +47,25 @@ class VprPbTypeAnnotation {
|
|||
e_interconnect interconnect_physical_type(t_interconnect* pb_interconnect) const;
|
||||
CircuitPortId pb_circuit_port(t_port* pb_port) const;
|
||||
std::vector<size_t> pb_type_mode_bits(t_pb_type* pb_type) const;
|
||||
/* Get the unique index of a pb_graph_node */
|
||||
PbGraphNodeId pb_graph_node_unique_index(t_pb_graph_node* pb_graph_node) const;
|
||||
/* Get the pointer to a pb_graph node using an unique index */
|
||||
t_pb_graph_node* pb_graph_node(t_pb_type* pb_type, const PbGraphNodeId& unique_index) const;
|
||||
t_pb_graph_node* physical_pb_graph_node(t_pb_graph_node* pb_graph_node) const;
|
||||
int physical_pb_type_index_factor(t_pb_type* pb_type) const;
|
||||
int physical_pb_type_index_offset(t_pb_type* pb_type) const;
|
||||
|
||||
int physical_pb_pin_rotate_offset(t_port* pb_port) const;
|
||||
|
||||
/**This function returns an accumulated offset. Note that the
|
||||
* accumulated offset is NOT the pin rotate offset specified by users
|
||||
* It is an aggregation of the offset during pin pairing
|
||||
* Each time, we manage to pair two pins, the accumulated offset will be incremented
|
||||
* by the pin rotate offset value
|
||||
* The accumulated offset will be reset to 0 when it exceeds the msb() of the physical port
|
||||
*/
|
||||
int physical_pb_pin_offset(t_port* pb_port) const;
|
||||
t_pb_graph_pin* physical_pb_graph_pin(t_pb_graph_pin* pb_graph_pin) 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);
|
||||
|
@ -49,9 +76,18 @@ class VprPbTypeAnnotation {
|
|||
void add_interconnect_physical_type(t_interconnect* pb_interconnect, const e_interconnect& physical_type);
|
||||
void add_pb_circuit_port(t_port* pb_port, const CircuitPortId& circuit_port);
|
||||
void add_pb_type_mode_bits(t_pb_type* pb_type, const std::vector<size_t>& mode_bits);
|
||||
void add_pb_graph_node_unique_index(t_pb_graph_node* pb_graph_node);
|
||||
void add_physical_pb_graph_node(t_pb_graph_node* operating_pb_graph_node,
|
||||
t_pb_graph_node* physical_pb_graph_node);
|
||||
void add_physical_pb_type_index_factor(t_pb_type* pb_type, const int& factor);
|
||||
void add_physical_pb_type_index_offset(t_pb_type* pb_type, const int& offset);
|
||||
void add_physical_pb_pin_rotate_offset(t_port* pb_port, const int& offset);
|
||||
void add_physical_pb_graph_pin(t_pb_graph_pin* operating_pb_graph_pin, t_pb_graph_pin* physical_pb_graph_pin);
|
||||
private: /* Internal data */
|
||||
/* 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*, int> physical_pb_type_index_factors_;
|
||||
std::map<t_pb_type*, int> physical_pb_type_index_offsets_;
|
||||
|
||||
/* Pair a physical mode for a pb_type
|
||||
* Note:
|
||||
|
@ -91,6 +127,10 @@ class VprPbTypeAnnotation {
|
|||
* - the parent of physical pb_port MUST be a physical pb_type
|
||||
*/
|
||||
std::map<t_port*, t_port*> physical_pb_ports_;
|
||||
std::map<t_port*, int> physical_pb_pin_rotate_offsets_;
|
||||
|
||||
/* Accumulated offsets for a physical pb_type port, just for internal usage */
|
||||
std::map<t_port*, int> physical_pb_pin_offsets_;
|
||||
|
||||
/* Pair a pb_port to its LSB and MSB of a physical pb_port
|
||||
* Note:
|
||||
|
@ -104,11 +144,19 @@ class VprPbTypeAnnotation {
|
|||
*/
|
||||
std::map<t_port*, CircuitPortId> pb_circuit_ports_;
|
||||
|
||||
/* Pair each pb_graph_node to an unique index in the graph
|
||||
* The unique index if the index in the array of t_pb_graph_node*
|
||||
*/
|
||||
std::map<t_pb_type*, std::vector<t_pb_graph_node*>> pb_graph_node_unique_index_;
|
||||
|
||||
/* 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_;
|
||||
|
||||
/* Pair a pb_graph_pin to a physical pb_graph_pin */
|
||||
std::map<t_pb_graph_pin*, t_pb_graph_pin*> physical_pb_graph_pins_;
|
||||
};
|
||||
|
||||
} /* End namespace openfpga*/
|
|
@ -1,122 +0,0 @@
|
|||
/********************************************************************
|
||||
* 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 */
|
||||
|
|
@ -39,7 +39,13 @@ void link_arch(OpenfpgaContext& openfpga_context) {
|
|||
annotate_pb_types(g_vpr_ctx.device(), openfpga_context.arch(),
|
||||
openfpga_context.mutable_vpr_pb_type_annotation());
|
||||
|
||||
/* Link routing architecture to circuit model */
|
||||
/* Annotate pb_graph_nodes
|
||||
* - Give unique index to each node in the same type
|
||||
* - Bind operating pb_graph_node to their physical pb_graph_node
|
||||
* - Bind pins from operating pb_graph_node to their physical pb_graph_node pins
|
||||
*/
|
||||
annotate_pb_graph(g_vpr_ctx.device(),
|
||||
openfpga_context.mutable_vpr_pb_type_annotation());
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -8,7 +8,7 @@ read_openfpga_arch -f ./test_openfpga_arch/k6_N10_40nm_openfpga.xml
|
|||
link_openfpga_arch
|
||||
|
||||
# Check and correct any naming conflicts in the BLIF netlist
|
||||
check_netlist_naming_conflict --fix --report ./netlist_renaming.rpt
|
||||
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
|
||||
|
||||
# Finish and exit OpenFPGA
|
||||
exit
|
||||
|
|
Loading…
Reference in New Issue