Merge branch 'refactoring' into dev

This commit is contained in:
tangxifan 2020-02-18 11:04:22 -07:00
commit 098f7dddf3
18 changed files with 1181 additions and 11 deletions

View File

@ -241,6 +241,14 @@ ArchDirectId VprDeviceAnnotation::direct_annotation(const size_t& direct) const
return direct_annotations_.at(direct);
}
LbRRGraph VprDeviceAnnotation::physical_lb_rr_graph(t_pb_graph_node* pb_graph_head) const {
/* Ensure that the rr_switch is in the list */
if (0 == physical_lb_rr_graphs_.count(pb_graph_head)) {
return LbRRGraph();
}
return physical_lb_rr_graphs_.at(pb_graph_head);
}
/************************************************************************
* Public mutators
***********************************************************************/
@ -470,4 +478,14 @@ void VprDeviceAnnotation::add_direct_annotation(const size_t& direct, const Arch
direct_annotations_[direct] = arch_direct_id;
}
void VprDeviceAnnotation::add_physical_lb_rr_graph(t_pb_graph_node* pb_graph_head, const LbRRGraph& lb_rr_graph) {
/* Warn any override attempt */
if (0 < physical_lb_rr_graphs_.count(pb_graph_head)) {
VTR_LOG_WARN("Override the physical lb_rr_graph for pb_graph_head '%s'!\n",
pb_graph_head->pb_type->name);
}
physical_lb_rr_graphs_[pb_graph_head] = lb_rr_graph;
}
} /* End namespace openfpga*/

View File

@ -19,6 +19,7 @@
#include "openfpga_port.h"
#include "circuit_library.h"
#include "arch_direct.h"
#include "lb_rr_graph.h"
/* Begin namespace openfpga */
namespace openfpga {
@ -73,6 +74,7 @@ class VprDeviceAnnotation {
CircuitModelId rr_switch_circuit_model(const RRSwitchId& rr_switch) const;
CircuitModelId rr_segment_circuit_model(const RRSegmentId& rr_segment) const;
ArchDirectId direct_annotation(const size_t& direct) const;
LbRRGraph physical_lb_rr_graph(t_pb_graph_node* pb_graph_head) 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);
@ -93,6 +95,7 @@ class VprDeviceAnnotation {
void add_rr_switch_circuit_model(const RRSwitchId& rr_switch, const CircuitModelId& circuit_model);
void add_rr_segment_circuit_model(const RRSegmentId& rr_segment, const CircuitModelId& circuit_model);
void add_direct_annotation(const size_t& direct, const ArchDirectId& arch_direct_id);
void add_physical_lb_rr_graph(t_pb_graph_node* pb_graph_head, const LbRRGraph& lb_rr_graph);
private: /* Internal data */
/* Pair a regular pb_type to its physical pb_type */
std::map<t_pb_type*, t_pb_type*> physical_pb_types_;
@ -176,6 +179,9 @@ class VprDeviceAnnotation {
/* Pair a direct connection (direct) to a annotation which contains circuit model id */
std::map<size_t, ArchDirectId> direct_annotations_;
/* Logical type routing resource graphs built from physical modes */
std::map<t_pb_graph_node*, LbRRGraph> physical_lb_rr_graphs_;
};
} /* End namespace openfpga*/

View File

@ -0,0 +1,38 @@
/********************************************************************
* Add commands to the OpenFPGA shell interface,
* in purpose of generate Verilog netlists modeling the full FPGA fabric
* This is one of the core engine of openfpga, including:
* - repack : create physical pbs and redo packing
*******************************************************************/
#include "openfpga_repack.h"
#include "openfpga_bitstream_command.h"
/* begin namespace openfpga */
namespace openfpga {
void add_openfpga_bitstream_commands(openfpga::Shell<OpenfpgaContext>& shell) {
/* Get the unique id of 'build_fabric' command which is to be used in creating the dependency graph */
const ShellCommandId& shell_cmd_build_fabric_id = shell.command(std::string("build_fabric"));
/* Add a new class of commands */
ShellCommandClassId openfpga_bitstream_cmd_class = shell.add_command_class("FPGA-Bitstream");
/********************************
* Command 'repack'
*/
Command shell_cmd_repack("repack");
/* Add an option '--verbose' */
shell_cmd_repack.add_option("verbose", false, "Enable verbose output");
/* Add command 'repack' to the Shell */
ShellCommandId shell_cmd_repack_id = shell.add_command(shell_cmd_repack, "Pack physical programmable logic blocks");
shell.set_command_class(shell_cmd_repack_id, openfpga_bitstream_cmd_class);
shell.set_command_execute_function(shell_cmd_repack_id, repack);
/* The 'repack' command should NOT be executed before 'build_fabric' */
std::vector<ShellCommandId> cmd_dependency_repack;
cmd_dependency_repack.push_back(shell_cmd_build_fabric_id);
shell.set_command_dependency(shell_cmd_repack_id, cmd_dependency_repack);
}
} /* end namespace openfpga */

View File

@ -0,0 +1,21 @@
#ifndef OPENFPGA_BITSTREAM_COMMAND_H
#define OPENFPGA_BITSTREAM_COMMAND_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "shell.h"
#include "openfpga_context.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void add_openfpga_bitstream_commands(openfpga::Shell<OpenfpgaContext>& shell);
} /* end namespace openfpga */
#endif

View File

@ -15,6 +15,7 @@
#include "annotate_rr_graph.h"
#include "mux_library_builder.h"
#include "build_tile_direct.h"
#include "build_physical_lb_rr_graph.h"
#include "openfpga_link_arch.h"
/* Include global variables of VPR */
@ -112,6 +113,10 @@ void link_arch(OpenfpgaContext& openfpga_ctx,
openfpga_ctx.mutable_tile_direct() = build_device_tile_direct(g_vpr_ctx.device(),
openfpga_ctx.arch().arch_direct);
build_physical_lb_rr_graphs(g_vpr_ctx.device(),
openfpga_ctx.mutable_vpr_device_annotation(),
cmd_context.option_enable(cmd, opt_verbose));
}
} /* end namespace openfpga */

View File

@ -0,0 +1,33 @@
/********************************************************************
* This file includes functions to compress the hierachy of routing architecture
*******************************************************************/
/* Headers from vtrutil library */
#include "vtr_time.h"
#include "vtr_log.h"
#include "verilog_api.h"
#include "repack.h"
#include "openfpga_repack.h"
/* Include global variables of VPR */
#include "globals.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* A wrapper function to call the fabric_verilog function of FPGA-Verilog
*******************************************************************/
void repack(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context) {
CommandOptionId opt_verbose = cmd.option("verbose");
pack_physical_pbs(g_vpr_ctx.device(),
openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.mutable_vpr_clustering_annotation(),
openfpga_ctx.vpr_routing_annotation(),
cmd_context.option_enable(cmd, opt_verbose));
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef OPENFPGA_REPACK_H
#define OPENFPGA_REPACK_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "command.h"
#include "command_context.h"
#include "openfpga_context.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void repack(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context);
} /* end namespace openfpga */
#endif

View File

@ -13,6 +13,7 @@
#include "vpr_command.h"
#include "openfpga_setup_command.h"
#include "openfpga_verilog_command.h"
#include "openfpga_bitstream_command.h"
#include "basic_command.h"
#include "openfpga_title.h"
@ -56,6 +57,9 @@ int main(int argc, char** argv) {
/* Add openfpga verilog commands */
openfpga::add_openfpga_verilog_commands(shell);
/* Add openfpga bitstream commands */
openfpga::add_openfpga_bitstream_commands(shell);
/* Add basic commands: exit, help, etc.
* Note:
* This MUST be the last command group to be added!

View File

@ -0,0 +1,404 @@
/***************************************************************************************
* This file includes functions that are used to redo packing for physical pbs
***************************************************************************************/
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
#include "pb_type_utils.h"
#include "build_physical_lb_rr_graph.h"
/* begin namespace openfpga */
namespace openfpga {
/***************************************************************************************
* Create all the intermediate nodes for lb_rr_graph for each pb_graph_node.
* Different from the lb_rr_graph builder in VPR packer, this function only consider
* the pb_graph_node under physical modes
***************************************************************************************/
static
void rec_build_physical_lb_rr_node_for_pb_graph_node(t_pb_graph_node* pb_graph_node,
LbRRGraph& lb_rr_graph,
const VprDeviceAnnotation& device_annotation) {
t_pb_type* pb_type = pb_graph_node->pb_type;
/* TODO: think if we need to consider wire mode of LUT when creating the lb_rr_graph here!
* Should we create edges through the LUT input and output nodes?
*/
/* The only difference between primitive node and intermediate nodes is
* the output pins of primitive node will be SINK node
* Otherwise it is always INTERMEDIATE node
*/
e_lb_rr_type output_pin_rr_type = LB_INTERMEDIATE;
if (true == is_primitive_pb_type(pb_type)) {
output_pin_rr_type = LB_SOURCE;
}
/* alloc and load input pins that connect to sinks */
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++) {
/* load intermediate indices */
t_pb_graph_pin* pb_pin = &pb_graph_node->input_pins[iport][ipin];
/* alloc and load rr node info */
LbRRNodeId node = lb_rr_graph.create_node(LB_INTERMEDIATE);
lb_rr_graph.set_node_capacity(node, 1);
lb_rr_graph.set_node_pb_graph_pin(node, pb_pin);
/* TODO: Double check if this is the case */
lb_rr_graph.set_node_intrinsic_cost(node, 1);
}
}
/* alloc and load input pins that connect to sinks */
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++) {
/* load intermediate indices */
t_pb_graph_pin* pb_pin = &pb_graph_node->clock_pins[iport][ipin];
/* alloc and load rr node info */
LbRRNodeId node = lb_rr_graph.create_node(LB_INTERMEDIATE);
lb_rr_graph.set_node_capacity(node, 1);
lb_rr_graph.set_node_pb_graph_pin(node, pb_pin);
/* TODO: Double check if this is the case */
lb_rr_graph.set_node_intrinsic_cost(node, 1);
}
}
/* alloc and load output pins that are represented as rr sources */
for (int iport = 0; iport < pb_graph_node->num_output_ports; iport++) {
for (int ipin = 0; ipin < pb_graph_node->num_output_pins[iport]; ipin++) {
/* load intermediate indices */
t_pb_graph_pin* pb_pin = &pb_graph_node->output_pins[iport][ipin];
/* alloc and load rr node info */
LbRRNodeId node = lb_rr_graph.create_node(output_pin_rr_type);
lb_rr_graph.set_node_capacity(node, 1);
lb_rr_graph.set_node_pb_graph_pin(node, pb_pin);
/* TODO: Double check if this is the case */
lb_rr_graph.set_node_intrinsic_cost(node, 1);
}
}
if (true == is_primitive_pb_type(pb_type)) {
return;
}
/* For non-primitive node:
* This pb_graph_node is a logic block or subcluster
* Go recusrively
*/
t_mode* physical_mode = device_annotation.physical_mode(pb_type);
for (int ipb_type = 0; ipb_type < physical_mode->num_pb_type_children; ipb_type++) {
for (int ipb = 0; ipb < physical_mode->pb_type_children[ipb_type].num_pb; ipb++) {
rec_build_physical_lb_rr_node_for_pb_graph_node(&(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb_type][ipb]), lb_rr_graph, device_annotation);
}
}
}
/***************************************************************************************
* Build the edge for an input/clock pb_graph_pin for a primitive pb_graph node
* This function will identify if the port equivalence should be considered
***************************************************************************************/
static
void build_lb_rr_edge_primitive_pb_graph_input_pin(LbRRGraph& lb_rr_graph,
t_pb_graph_pin* pb_pin,
LbRRNodeId& sink_node) {
/* Find the node that we have already created */
LbRRNodeId node = lb_rr_graph.find_node(LB_INTERMEDIATE, pb_pin);
VTR_ASSERT(true == lb_rr_graph.valid_node_id(node));
PortEquivalence port_equivalent = pb_pin->port->equivalent;
if (port_equivalent == PortEquivalence::NONE || sink_node == LbRRNodeId::INVALID()) {
/* Create new sink for input to primitive */
LbRRNodeId new_sink = lb_rr_graph.create_node(LB_SINK);
if (port_equivalent != PortEquivalence::NONE) {
lb_rr_graph.set_node_capacity(new_sink, pb_pin->port->num_pins);
} else {
lb_rr_graph.set_node_capacity(new_sink, 1);
}
sink_node = new_sink;
}
/* Connect the nodes denoting the input pins to sink, since this is a primtive node, we do not have any mode */
LbRREdgeId edge = lb_rr_graph.create_edge(node, sink_node, nullptr);
/* TODO: Double check if this is the case */
lb_rr_graph.set_edge_intrinsic_cost(edge, 1.);
}
/***************************************************************************************
* Build the edge for a pb_graph_pin for a non-primitive pb_graph node
* Note:
* - this function is NOT applicable to
* - any input pin of primitive pb_graph_node
* - any output pin of root pb_graph_node!
***************************************************************************************/
static
void build_lb_rr_edge_pb_graph_pin(LbRRGraph& lb_rr_graph,
t_pb_graph_pin* pb_pin,
const e_lb_rr_type& pin_rr_type,
t_mode* physical_mode) {
/* Find the node that we have already created */
LbRRNodeId from_node = lb_rr_graph.find_node(pin_rr_type, pb_pin);
VTR_ASSERT(true == lb_rr_graph.valid_node_id(from_node));
/* Load edges only for physical mode! */
for (int iedge = 0; iedge < pb_pin->num_output_edges; iedge++) {
VTR_ASSERT(1 == pb_pin->output_edges[iedge]->num_output_pins);
if (physical_mode != pb_pin->output_edges[iedge]->interconnect->parent_mode) {
continue;
}
/* Find the node that we have already created */
LbRRNodeId to_node = lb_rr_graph.find_node(LB_INTERMEDIATE, pb_pin->output_edges[iedge]->output_pins[0]);
VTR_ASSERT(true == lb_rr_graph.valid_node_id(to_node));
LbRREdgeId edge = lb_rr_graph.create_edge(from_node, to_node, physical_mode);
/* TODO: Double check if this is the case */
lb_rr_graph.set_edge_intrinsic_cost(edge, 1.);
}
}
/***************************************************************************************
* Build the edge for an output pb_graph_pin for a root pb_graph node
* These node should be connected to a command external lb_rr_node
***************************************************************************************/
static
void build_lb_rr_edge_root_pb_graph_pin(LbRRGraph& lb_rr_graph,
t_pb_graph_pin* pb_pin,
const e_lb_rr_type& pin_rr_type,
const LbRRNodeId& ext_rr_index) {
/* Find the node that we have already created */
LbRRNodeId from_node = lb_rr_graph.find_node(pin_rr_type, pb_pin);
VTR_ASSERT(true == lb_rr_graph.valid_node_id(from_node));
LbRREdgeId edge = lb_rr_graph.create_edge(from_node, ext_rr_index, nullptr);
/* TODO: Double check if this is the case */
lb_rr_graph.set_edge_intrinsic_cost(edge, 1.);
}
/***************************************************************************************
* Create all the edges and special nodes (SOURCE/SINK) for lb_rr_graph for each pb_graph_node.
* Different from the lb_rr_graph builder in VPR packer, this function only consider
* the pb_graph_node under physical modes
***************************************************************************************/
static
void rec_build_physical_lb_rr_edge_for_pb_graph_node(t_pb_graph_node* pb_graph_node,
LbRRGraph& lb_rr_graph,
const LbRRNodeId& ext_rr_index,
const VprDeviceAnnotation& device_annotation) {
t_pb_type* pb_type = pb_graph_node->pb_type;
t_pb_graph_node* parent_node = pb_graph_node->parent_pb_graph_node;
/* TODO: think if we need to consider wire mode of LUT when creating the lb_rr_graph here!
* Should we create edges through the LUT input and output nodes?
*/
/* The only difference between primitive node and intermediate nodes is
* the output pins of primitive node will be SINK node
* Otherwise it is always INTERMEDIATE node
*/
/* The input pins should connect to sinks */
for (int iport = 0; iport < pb_graph_node->num_input_ports; iport++) {
LbRRNodeId sink_node = LbRRNodeId::INVALID();
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ipin++) {
/* load intermediate indices */
t_pb_graph_pin* pb_pin = &pb_graph_node->input_pins[iport][ipin];
t_mode* physical_mode = device_annotation.physical_mode(pb_type);
if (true == is_primitive_pb_type(pb_type)) {
build_lb_rr_edge_primitive_pb_graph_input_pin(lb_rr_graph, pb_pin, sink_node);
} else {
VTR_ASSERT(false == is_primitive_pb_type(pb_type));
build_lb_rr_edge_pb_graph_pin(lb_rr_graph, pb_pin, LB_INTERMEDIATE, physical_mode);
}
}
}
/* The input pins should connect to sinks */
for (int iport = 0; iport < pb_graph_node->num_clock_ports; iport++) {
LbRRNodeId sink_node = LbRRNodeId::INVALID();
for (int ipin = 0; ipin < pb_graph_node->num_clock_pins[iport]; ipin++) {
/* load intermediate indices */
t_pb_graph_pin* pb_pin = &pb_graph_node->clock_pins[iport][ipin];
t_mode* physical_mode = device_annotation.physical_mode(pb_type);
if (true == is_primitive_pb_type(pb_type)) {
build_lb_rr_edge_primitive_pb_graph_input_pin(lb_rr_graph, pb_pin, sink_node);
} else {
VTR_ASSERT(false == is_primitive_pb_type(pb_type));
build_lb_rr_edge_pb_graph_pin(lb_rr_graph, pb_pin, LB_INTERMEDIATE, physical_mode);
}
}
}
e_lb_rr_type output_pin_rr_type = LB_INTERMEDIATE;
if (true == is_primitive_pb_type(pb_type)) {
output_pin_rr_type = LB_SOURCE;
}
/* The output pins should connect to its fan-outs */
for (int iport = 0; iport < pb_graph_node->num_output_ports; iport++) {
for (int ipin = 0; ipin < pb_graph_node->num_output_pins[iport]; ipin++) {
/* load intermediate indices */
t_pb_graph_pin* pb_pin = &pb_graph_node->output_pins[iport][ipin];
if (true == pb_graph_node->is_root()) {
build_lb_rr_edge_root_pb_graph_pin(lb_rr_graph, pb_pin, output_pin_rr_type, ext_rr_index);
} else {
VTR_ASSERT(false == pb_graph_node->is_root());
t_mode* physical_mode = device_annotation.physical_mode(parent_node->pb_type);
build_lb_rr_edge_pb_graph_pin(lb_rr_graph, pb_pin, output_pin_rr_type, physical_mode);
}
}
}
if (true == is_primitive_pb_type(pb_type)) {
return;
}
/* For non-primitive node:
* This pb_graph_node is a logic block or subcluster
* Go recusrively
*/
t_mode* physical_mode = device_annotation.physical_mode(pb_graph_node->pb_type);
for (int ipb_type = 0; ipb_type < physical_mode->num_pb_type_children; ipb_type++) {
for (int ipb = 0; ipb < physical_mode->pb_type_children[ipb_type].num_pb; ipb++) {
rec_build_physical_lb_rr_edge_for_pb_graph_node(&(pb_graph_node->child_pb_graph_nodes[physical_mode->index][ipb_type][ipb]), lb_rr_graph, ext_rr_index, device_annotation);
}
}
}
/***************************************************************************************
* This functio will create a physical lb_rr_graph for a pb_graph considering physical modes only
***************************************************************************************/
static
LbRRGraph build_lb_type_physical_lb_rr_graph(t_pb_graph_node* pb_graph_head,
const VprDeviceAnnotation& device_annotation,
const bool& verbose) {
LbRRGraph lb_rr_graph;
/* TODO: ensure we have an empty lb_rr_graph */
/* Define the external source, sink, and external interconnect for the routing resource graph of the logic block type */
LbRRNodeId ext_source_index = lb_rr_graph.create_node(LB_SOURCE);
LbRRNodeId ext_sink_index = lb_rr_graph.create_node(LB_SINK);
LbRRNodeId ext_rr_index = lb_rr_graph.create_node(LB_INTERMEDIATE);
/* Build the main body of lb rr_graph by walking through the pb_graph recursively */
/* Build all the regular nodes first */
rec_build_physical_lb_rr_node_for_pb_graph_node(pb_graph_head, lb_rr_graph, device_annotation);
/* Build all the edges and special node (SOURCE/SINK) */
rec_build_physical_lb_rr_edge_for_pb_graph_node(pb_graph_head, lb_rr_graph, ext_rr_index, device_annotation);
/*******************************************************************************
* Build logic block source node
*******************************************************************************/
t_pb_type* pb_type = pb_graph_head->pb_type;
/* External source node drives all inputs going into logic block type */
lb_rr_graph.set_node_capacity(ext_source_index, pb_type->num_input_pins + pb_type->num_clock_pins);
for (int iport = 0; iport < pb_graph_head->num_input_ports; iport++) {
for (int ipin = 0; ipin < pb_graph_head->num_input_pins[iport]; ipin++) {
LbRRNodeId to_node = lb_rr_graph.find_node(LB_INTERMEDIATE, &(pb_graph_head->input_pins[iport][ipin]));
VTR_ASSERT(true == lb_rr_graph.valid_node_id(to_node));
LbRREdgeId edge = lb_rr_graph.create_edge(ext_source_index, to_node, nullptr);
lb_rr_graph.set_edge_intrinsic_cost(edge, 1.);
}
}
for (int iport = 0; iport < pb_graph_head->num_clock_ports; iport++) {
for (int ipin = 0; ipin < pb_graph_head->num_clock_pins[iport]; ipin++) {
LbRRNodeId to_node = lb_rr_graph.find_node(LB_INTERMEDIATE, &(pb_graph_head->clock_pins[iport][ipin]));
VTR_ASSERT(true == lb_rr_graph.valid_node_id(to_node));
LbRREdgeId edge = lb_rr_graph.create_edge(ext_source_index, to_node, nullptr);
lb_rr_graph.set_edge_intrinsic_cost(edge, 1.);
}
}
/*******************************************************************************
* Build logic block sink node
*******************************************************************************/
/* External sink node driven by all outputs exiting logic block type */
lb_rr_graph.set_node_capacity(ext_sink_index, pb_type->num_output_pins);
/*******************************************************************************
* Build node that approximates external interconnect
*******************************************************************************/
/* External rr node that drives all existing logic block input pins and is driven by all outputs exiting logic block type */
lb_rr_graph.set_node_capacity(ext_rr_index, pb_type->num_output_pins);
/* Connect opin of logic block to sink */
{
LbRREdgeId edge = lb_rr_graph.create_edge(ext_rr_index, ext_sink_index, nullptr);
lb_rr_graph.set_edge_intrinsic_cost(edge, 1.);
}
/* Connect opin of logic block to all input and clock pins of logic block type */
for (int iport = 0; iport < pb_graph_head->num_input_ports; iport++) {
for (int ipin = 0; ipin < pb_graph_head->num_input_pins[iport]; ipin++) {
LbRRNodeId to_node = lb_rr_graph.find_node(LB_INTERMEDIATE, &(pb_graph_head->input_pins[iport][ipin]));
VTR_ASSERT(true == lb_rr_graph.valid_node_id(to_node));
LbRREdgeId edge = lb_rr_graph.create_edge(ext_rr_index, to_node, nullptr);
/* set cost high to avoid using external interconnect unless necessary */
lb_rr_graph.set_edge_intrinsic_cost(edge, 1000.);
}
}
for (int iport = 0; iport < pb_graph_head->num_clock_ports; iport++) {
for (int ipin = 0; ipin < pb_graph_head->num_clock_pins[iport]; ipin++) {
LbRRNodeId to_node = lb_rr_graph.find_node(LB_INTERMEDIATE, &(pb_graph_head->clock_pins[iport][ipin]));
VTR_ASSERT(true == lb_rr_graph.valid_node_id(to_node));
LbRREdgeId edge = lb_rr_graph.create_edge(ext_rr_index, to_node, nullptr);
/* set cost high to avoid using external interconnect unless necessary */
lb_rr_graph.set_edge_intrinsic_cost(edge, 1000.);
}
}
VTR_LOGV(verbose,
"\n\tNumber of nodes: %lu\n",
lb_rr_graph.nodes().size());
VTR_LOGV(verbose,
"\tNumber of edges: %lu\n",
lb_rr_graph.edges().size());
return lb_rr_graph;
}
/***************************************************************************************
* This functio will create physical lb_rr_graph for each pb_graph considering physical modes only
* the lb_rr_graph willbe added to device annotation
***************************************************************************************/
void build_physical_lb_rr_graphs(const DeviceContext& device_ctx,
VprDeviceAnnotation& device_annotation,
const bool& verbose) {
vtr::ScopedStartFinishTimer timer("Build routing resource graph for the physical implementation of logical tile");
for (const t_logical_block_type& lb_type : device_ctx.logical_block_types) {
/* By pass nullptr for pb_graph head */
if (nullptr == lb_type.pb_graph_head) {
continue;
}
VTR_LOGV(verbose,
"Building routing resource graph for logical tile '%s'...",
lb_type.pb_graph_head->pb_type->name);
const LbRRGraph& lb_rr_graph = build_lb_type_physical_lb_rr_graph(lb_type.pb_graph_head, const_cast<const VprDeviceAnnotation&>(device_annotation), verbose);
device_annotation.add_physical_lb_rr_graph(lb_type.pb_graph_head, lb_rr_graph);
}
VTR_LOGV(verbose, "Done\n");
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef BUILD_PHYSICAL_LB_RR_GRAPH_H
#define BUILD_PHYSICAL_LB_RR_GRAPH_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "vpr_device_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void build_physical_lb_rr_graphs(const DeviceContext& device_ctx,
VprDeviceAnnotation& device_annotation,
const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,215 @@
/************************************************************************
* Member Functions of LbRRGraph
* include mutators, accessors and utility functions
***********************************************************************/
#include "vtr_assert.h"
#include "vtr_log.h"
#include "lb_rr_graph.h"
/* begin namespace openfpga */
namespace openfpga {
/**************************************************
* Public Accessors: Aggregates
*************************************************/
LbRRGraph::node_range LbRRGraph::nodes() const {
return vtr::make_range(node_ids_.begin(), node_ids_.end());
}
LbRRGraph::edge_range LbRRGraph::edges() const {
return vtr::make_range(edge_ids_.begin(), edge_ids_.end());
}
/**************************************************
* Public Accessors node-level attributes
*************************************************/
e_lb_rr_type LbRRGraph::node_type(const LbRRNodeId& node) const {
VTR_ASSERT(true == valid_node_id(node));
return node_types_[node];
}
short LbRRGraph::node_capacity(const LbRRNodeId& node) const {
VTR_ASSERT(true == valid_node_id(node));
return node_capacities_[node];
}
t_pb_graph_pin* LbRRGraph::node_pb_graph_pin(const LbRRNodeId& node) const {
VTR_ASSERT(true == valid_node_id(node));
return node_pb_graph_pins_[node];
}
float LbRRGraph::node_intrinsic_cost(const LbRRNodeId& node) const {
VTR_ASSERT(true == valid_node_id(node));
return node_intrinsic_costs_[node];
}
std::vector<LbRREdgeId> LbRRGraph::node_in_edges(const LbRRNodeId& node, t_mode* mode) const {
std::vector<LbRREdgeId> in_edges;
VTR_ASSERT(true == valid_node_id(node));
for (const LbRREdgeId& edge : node_in_edges_[node]) {
if (mode == edge_mode(edge)) {
in_edges.push_back(edge);
}
}
return in_edges;
}
std::vector<LbRREdgeId> LbRRGraph::node_out_edges(const LbRRNodeId& node, t_mode* mode) const {
std::vector<LbRREdgeId> out_edges;
VTR_ASSERT(true == valid_node_id(node));
for (const LbRREdgeId& edge : node_out_edges_[node]) {
if (mode == edge_mode(edge)) {
out_edges.push_back(edge);
}
}
return out_edges;
}
LbRRNodeId LbRRGraph::find_node(const e_lb_rr_type& type, t_pb_graph_pin* pb_graph_pin) const {
if (size_t(type) >= node_lookup_.size()) {
return LbRRNodeId::INVALID();
}
if (0 == node_lookup_[size_t(type)].count(pb_graph_pin)) {
return LbRRNodeId::INVALID();
}
return node_lookup_[size_t(type)].at(pb_graph_pin);
}
LbRRNodeId LbRRGraph::edge_src_node(const LbRREdgeId& edge) const {
VTR_ASSERT(true == valid_edge_id(edge));
return edge_src_nodes_[edge];
}
LbRRNodeId LbRRGraph::edge_sink_node(const LbRREdgeId& edge) const {
VTR_ASSERT(true == valid_edge_id(edge));
return edge_sink_nodes_[edge];
}
float LbRRGraph::edge_intrinsic_cost(const LbRREdgeId& edge) const {
VTR_ASSERT(true == valid_edge_id(edge));
return edge_intrinsic_costs_[edge];
}
t_mode* LbRRGraph::edge_mode(const LbRREdgeId& edge) const {
VTR_ASSERT(true == valid_edge_id(edge));
return edge_modes_[edge];
}
/******************************************************************************
* Public Mutators
******************************************************************************/
void LbRRGraph::reserve_nodes(const unsigned long& num_nodes) {
node_ids_.reserve(num_nodes);
node_types_.reserve(num_nodes);
node_capacities_.reserve(num_nodes);
node_pb_graph_pins_.reserve(num_nodes);
node_intrinsic_costs_.reserve(num_nodes);
node_in_edges_.reserve(num_nodes);
node_out_edges_.reserve(num_nodes);
}
void LbRRGraph::reserve_edges(const unsigned long& num_edges) {
edge_ids_.reserve(num_edges);
edge_intrinsic_costs_.reserve(num_edges);
edge_modes_.reserve(num_edges);
edge_src_nodes_.reserve(num_edges);
edge_sink_nodes_.reserve(num_edges);
}
LbRRNodeId LbRRGraph::create_node(const e_lb_rr_type& type) {
/* Create an new id */
LbRRNodeId node = LbRRNodeId(node_ids_.size());
node_ids_.push_back(node);
/* Allocate other attributes */
node_types_.push_back(type);
node_capacities_.push_back(-1);
node_pb_graph_pins_.push_back(nullptr);
node_intrinsic_costs_.push_back(0.);
node_in_edges_.emplace_back();
node_out_edges_.emplace_back();
return node;
}
void LbRRGraph::set_node_type(const LbRRNodeId& node, const e_lb_rr_type& type) {
VTR_ASSERT(true == valid_node_id(node));
node_types_[node] = type;
}
void LbRRGraph::set_node_capacity(const LbRRNodeId& node, const short& capacity) {
VTR_ASSERT(true == valid_node_id(node));
node_capacities_[node] = capacity;
}
void LbRRGraph::set_node_pb_graph_pin(const LbRRNodeId& node, t_pb_graph_pin* pb_graph_pin) {
VTR_ASSERT(true == valid_node_id(node));
node_pb_graph_pins_[node] = pb_graph_pin;
/* Register in fast node look-up */
if (node_type(node) >= node_lookup_.size()) {
node_lookup_.resize(node_type(node) + 1);
}
if (0 < node_lookup_[node_type(node)].count(pb_graph_pin)) {
VTR_LOG_WARN("Detect pb_graph_pin '%s[%lu]' is mapped to LbRRGraph nodes (exist: %lu) and (to be mapped: %lu). Overwrite is done\n",
pb_graph_pin->port->name, pb_graph_pin->pin_number,
size_t(node_lookup_[node_type(node)].at(pb_graph_pin)),
size_t(node));
}
node_lookup_[node_type(node)][pb_graph_pin] = node;
}
void LbRRGraph::set_node_intrinsic_cost(const LbRRNodeId& node, const float& cost) {
VTR_ASSERT(true == valid_node_id(node));
node_intrinsic_costs_[node] = cost;
}
LbRREdgeId LbRRGraph::create_edge(const LbRRNodeId& source,
const LbRRNodeId& sink,
t_mode* mode) {
VTR_ASSERT(true == valid_node_id(source));
VTR_ASSERT(true == valid_node_id(sink));
/* Create an new id */
LbRREdgeId edge = LbRREdgeId(edge_ids_.size());
edge_ids_.push_back(edge);
/* Allocate other attributes */
edge_src_nodes_.push_back(source);
edge_sink_nodes_.push_back(sink);
edge_intrinsic_costs_.push_back(0.);
edge_modes_.push_back(mode);
node_out_edges_[source].push_back(edge);
node_in_edges_[sink].push_back(edge);
return edge;
}
void LbRRGraph::set_edge_intrinsic_cost(const LbRREdgeId& edge, const float& cost) {
VTR_ASSERT(true == valid_edge_id(edge));
edge_intrinsic_costs_[edge] = cost;
}
/******************************************************************************
* Public validators/invalidators
******************************************************************************/
bool LbRRGraph::valid_node_id(const LbRRNodeId& node_id) const {
return ( size_t(node_id) < node_ids_.size() ) && ( node_id == node_ids_[node_id] );
}
bool LbRRGraph::valid_edge_id(const LbRREdgeId& edge_id) const {
return ( size_t(edge_id) < edge_ids_.size() ) && ( edge_id == edge_ids_[edge_id] );
}
} /* end namespace openfpga */

View File

@ -0,0 +1,296 @@
/************************************************************************
* This file introduces a class to model a Routing Resource Graph (RRGraph or RRG)
* which is used by packer.
*
* Overview
* ========
* RRGraph aims to describe in a general way how routing resources are connected
* inside a pb_graph
*
* A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many cycles),
* which consists of a number of nodes and edges.
*
* Node
* ----
* Each node represents a routing resource, which could be
* 1. an intermediate node(INTERMEDIATE_NODE), which are input/output pins of non-primitive and non-root pb_graph_nodes. It represents a pb_graph_pin that exists in a pb_graph
* 2. a virtual source (SOURCE), which are inputs of root pb_graph_nodes or outputs of primitive pb_graph_node
* 3. a sink node (SINK), which are outputs of root pb_graph_nodes or inputs or primitive pb_graph_node
*
* Edge
* ----
* Each edge represents a connection between two pb_graph_pins
* It represents a pb_graph_edge in a pb_graph
*
* Guidlines on using the LbRRGraph data structure
* =============================================
*
* For those want to access data from RRGraph
* ------------------------------------------
* Some examples for most frequent data query:
*
* // Strongly suggest to use a read-only lb_rr_graph object
* const LbRRGraph& lb_rr_graph;
*
* // Access type of a node with a given node id
* // Get the unique node id that you may get
* // from other data structures or functions
* LbRRNodeId node_id;
* e_lb_rr_type node_type = lb_rr_graph.node_type(node_id);
*
* // Access all the fan-out edges from a given node
* for (const RREdgeId& out_edge_id : rr_graph.node_out_edges(node_id)) {
* // Do something with out_edge
* }
* // If you only want to learn the number of fan-out edges
* size_t num_out_edges = rr_graph.node_fan_out(node_id);
*
* Please refer to the detailed comments on each public accessors
*
* For those want to build/modify a LbRRGraph
* -----------------------------------------
* Do NOT add a builder to this data structure!
* Builders should be kept as free functions that use the public mutators
* We suggest developers to create builders in separated C/C++ source files
* outside the rr_graph header and source files
*
* After build/modify a RRGraph, please do run a fundamental check, a public accessor.
* to ensure that your RRGraph does not include invalid nodes/edges/switches/segements
* as well as connections.
* The validate() function gurantees the consistency between internal data structures,
* such as the id cross-reference between nodes and edges etc.,
* so failing it indicates a fatal bug!
* This is a must-do check!
*
* Example:
* RRGraph lb_rr_graph;
* ... // Building RRGraph
* lb_rr_graph.validate();
*
* Optionally, we strongly recommend developers to run an advance check in check_rr_graph()
* This guarantees legal and routable RRGraph for VPR routers.
*
* This checks for connectivity or other information in the RRGraph that is unexpected
* or unusual in an FPGA, and likely indicates a problem in your graph generation.
* However, if you are intentionally creating an RRGraph with this unusual,
* buts still technically legal, behaviour, you can write your own check_rr_graph() with weaker assumptions.
*
* Note: Do NOT modify the coordinate system for nodes, they are designed for downstream drawers and routers
*
* For those want to extend RRGraph data structure
* --------------------------------------------------------------------------
* Please avoid modifying any existing public/private accessors/mutators
* in order to keep a stable RRGraph object in the framework
* Developers may add more internal data to RRGraph as well as associate accessors/mutators
* Please update and comment on the added features properly to keep this data structure friendly to be extended.
*
* Try to keep your extension within only graph-related internal data to RRGraph.
* In other words, extension is necessary when the new node/edge attributes are needed.
* RRGraph should NOT include other data which are shared by other data structures outside.
* The rr-graph is the single largest data structure in VPR,
* so avoid adding unnecessary information per node or per edge to it, as it will impact memory footprint.
* Instead, using indices to point to the outside data source instead of embedding to RRGraph
* For example:
* For any placement/routing cost related information, try to extend t_rr_indexed_data, but not RRGraph
* For any placement/routing results, try to extend PlaceContext and RoutingContext, but not RRGraph
*
* For those want to develop placers or routers
* --------------------------------------------------------------------------
* The RRGraph is designed to be a read-only database/graph, once created.
* Placement and routing should NOT change any attributes of RRGraph.
* Any placement and routing results should be stored in other data structures, such as PlaceContext and RoutingContext.
*
* Tracing Cross-Reference
* =======================
* RRGraph is designed to a self-contained data structure as much as possible.
* It includes the switch information (rr_switch) and segment_information (rr_segment)
* which are necessary to build-up any external data structures.
*
* Internal cross-reference
* ------------------------
*
* +--------+ +--------+
* | | node_in_edges | |
* | | node_out_edges | |
* | Node |----------------->| Edge |
* | |<-----------------| |
* | | edge_src_node | |
* +--------+ edge_sink_node +--------+
*
*
* External cross-reference
* ------------------------
* The only cross-reference to outside data structures is the cost_index
* corresponding to the data structure t_rr_index_data
* Details can be found in the definition of t_rr_index_data
* This allows rapid look up by the router of additional information it needs for this node, using a flyweight pattern.
*
* +---------+ pb_graph_pin +----------------+
* | RRGraph |---------------->| Pb_graph_node |
* +---------+ pb_graph_edge +----------------+
*
***********************************************************************/
#ifndef LB_RR_GRAPH_OBJ_H
#define LB_RR_GRAPH_OBJ_H
/*
* Notes in include header files in a head file
* Only include the neccessary header files
* that is required by the data types in the function/class declarations!
*/
/* Header files should be included in a sequence */
/* Standard header files required go first */
#include <limits>
#include <vector>
/* Header from vtrutil library */
#include "vtr_range.h"
#include "vtr_vector.h"
/* Header from readarch library */
#include "physical_types.h"
/* Header from vpr library */
#include "lb_rr_graph_types.h"
#include "lb_rr_graph_fwd.h"
/* begin namespace openfpga */
namespace openfpga {
class LbRRGraph {
public: /* Types */
/* Iterators used to create iterator-based loop for nodes/edges/switches/segments */
typedef vtr::vector<LbRRNodeId, LbRRNodeId>::const_iterator node_iterator;
typedef vtr::vector<LbRREdgeId, LbRREdgeId>::const_iterator edge_iterator;
/* Ranges used to create range-based loop for nodes/edges/switches/segments */
typedef vtr::Range<node_iterator> node_range;
typedef vtr::Range<edge_iterator> edge_range;
public: /* Accessors */
/* Aggregates: create range-based loops for nodes/edges/switches/segments
* To iterate over the nodes/edges/switches/segments in a RRGraph,
* using a range-based loop is suggested.
* -----------------------------------------------------------------
* Example: iterate over all the nodes
* // Strongly suggest to use a read-only rr_graph object
* const LbRRGraph& lb_rr_graph;
* for (const LbRRNodeId& node : lb_rr_graph.nodes()) {
* // Do something with each node
* }
*
* for (const LbRREdgeId& edge : lb_rr_graph.edges()) {
* // Do something with each edge
* }
*
*/
node_range nodes() const;
edge_range edges() const;
/* Node-level attributes */
e_lb_rr_type node_type(const LbRRNodeId& node) const;
short node_capacity(const LbRRNodeId& node) const;
t_pb_graph_pin* node_pb_graph_pin(const LbRRNodeId& node) const;
float node_intrinsic_cost(const LbRRNodeId& node) const;
/* Get a list of edge ids, which are incoming edges to a node */
std::vector<LbRREdgeId> node_in_edges(const LbRRNodeId& node, t_mode* mode) const;
/* Get a list of edge ids, which are outgoing edges from a node */
std::vector<LbRREdgeId> node_out_edges(const LbRRNodeId& node, t_mode* mode) const;
LbRRNodeId find_node(const e_lb_rr_type& type, t_pb_graph_pin* pb_graph_pin) const;
/* Get the source node which drives a edge */
LbRRNodeId edge_src_node(const LbRREdgeId& edge) const;
/* Get the sink node which a edge ends to */
LbRRNodeId edge_sink_node(const LbRREdgeId& edge) const;
float edge_intrinsic_cost(const LbRREdgeId& edge) const;
t_mode* edge_mode(const LbRREdgeId& edge) const;
public: /* Mutators */
/* Reserve the lists of nodes, edges, switches etc. to be memory efficient.
* This function is mainly used to reserve memory space inside RRGraph,
* when adding a large number of nodes/edge/switches/segments,
* in order to avoid memory fragements
* For example:
* LbRRGraph lb_rr_graph;
* // Add 1000 CHANX nodes to the LbRRGraph object
* rr_graph.reserve_nodes(1000);
* for (size_t i = 0; i < 1000; ++i) {
* rr_graph.create_node(CHANX);
* }
*/
void reserve_nodes(const unsigned long& num_nodes);
void reserve_edges(const unsigned long& num_edges);
/* Add new elements (node, edge, switch, etc.) to RRGraph */
/* Add a node to the RRGraph with a deposited type
* Detailed node-level information should be added using the set_node_* functions
* For example:
* RRNodeId node = create_node();
* set_node_xlow(node, 0);
*/
LbRRNodeId create_node(const e_lb_rr_type& type);
/* Set node-level information */
void set_node_type(const LbRRNodeId& node, const e_lb_rr_type& type);
void set_node_capacity(const LbRRNodeId& node, const short& capacity);
void set_node_pb_graph_pin(const LbRRNodeId& node, t_pb_graph_pin* pb_graph_pin);
void set_node_intrinsic_cost(const LbRRNodeId& node, const float& cost);
/* Add a edge to the RRGraph, by providing the source and sink node
* This function will automatically create a node and
* configure the nodes and edges in connection
*/
LbRREdgeId create_edge(const LbRRNodeId& source, const LbRRNodeId& sink, t_mode* mode);
void set_edge_intrinsic_cost(const LbRREdgeId& edge, const float& cost);
public: /* Validators */
/* Validate is the node id does exist in the RRGraph */
bool valid_node_id(const LbRRNodeId& node) const;
/* Validate is the edge id does exist in the RRGraph */
bool valid_edge_id(const LbRREdgeId& edge) const;
private: /* Internal Data */
/* Node related data */
vtr::vector<LbRRNodeId, LbRRNodeId> node_ids_;
vtr::vector<LbRRNodeId, e_lb_rr_type> node_types_;
vtr::vector<LbRRNodeId, short> node_capacities_;
vtr::vector<LbRRNodeId, t_pb_graph_pin*> node_pb_graph_pins_;
vtr::vector<LbRRNodeId, float> node_intrinsic_costs_;
/* Edges per node is sorted by modes: [<mode_id>][<in_edges...><out_edges>] */
vtr::vector<LbRRNodeId, std::vector<LbRREdgeId>> node_in_edges_;
vtr::vector<LbRRNodeId, std::vector<LbRREdgeId>> node_out_edges_;
/* Edge related data */
/* Range of edge ids, use the unsigned long as
* the number of edges could be >10 times larger than the number of nodes!
*/
vtr::vector<LbRREdgeId, LbRREdgeId> edge_ids_;
vtr::vector<LbRREdgeId, LbRRNodeId> edge_src_nodes_;
vtr::vector<LbRREdgeId, LbRRNodeId> edge_sink_nodes_;
vtr::vector<LbRREdgeId, float> edge_intrinsic_costs_;
vtr::vector<LbRREdgeId, t_mode*> edge_modes_;
/* Fast look-up to search a node by its type, coordinator and ptc_num
* Indexing of fast look-up: [0..NUM_TYPES-1][t_pb_graph_pin*]
*/
typedef std::vector<std::map<t_pb_graph_pin*, LbRRNodeId>> NodeLookup;
mutable NodeLookup node_lookup_;
};
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,19 @@
#ifndef LB_RR_GRAPH_OBJ_FWD_H
#define LB_RR_GRAPH_OBJ_FWD_H
#include "vtr_strong_id.h"
/***************************************************************
* This file includes a light declaration for the class LbRRGraph
* For a detailed description and how to use the class LbRRGraph,
* please refer to lb_rr_graph_obj.h
***************************************************************/
class LbRRGraph;
struct lb_rr_node_id_tag;
struct lb_rr_edge_id_tag;
typedef vtr::StrongId<lb_rr_node_id_tag> LbRRNodeId;
typedef vtr::StrongId<lb_rr_edge_id_tag> LbRREdgeId;
#endif

View File

@ -0,0 +1,32 @@
/***************************************************************************************
* This file includes functions that are used to redo packing for physical pbs
***************************************************************************************/
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
#include "repack.h"
/* begin namespace openfpga */
namespace openfpga {
/***************************************************************************************
* Top-level function to pack physical pb_graph
* This function will do :
* - create physical lb_rr_graph for each pb_graph considering physical modes only
* the lb_rr_graph willbe added to device annotation
* - annotate nets to be routed for each clustered block from operating modes of pb_graph
* to physical modes of pb_graph
* - rerun the routing for each clustered block
* - store the packing results to clustering annotation
***************************************************************************************/
void pack_physical_pbs(const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation,
VprClusteringAnnotation& clustering_annotation,
const VprRoutingAnnotation& routing_annotation,
const bool& verbose) {
}
} /* end namespace openfpga */

View File

@ -0,0 +1,27 @@
#ifndef REPACK_H
#define REPACK_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "vpr_device_annotation.h"
#include "vpr_clustering_annotation.h"
#include "vpr_routing_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void pack_physical_pbs(const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation,
VprClusteringAnnotation& clustering_annotation,
const VprRoutingAnnotation& routing_annotation,
const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -5,7 +5,7 @@ vpr ./test_vpr_arch/k6_frac_N10_40nm.xml ./test_blif/s298.blif --write_rr_graph
read_openfpga_arch -f ./test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml
# Annotate the OpenFPGA architecture to VPR data base
link_openfpga_arch
link_openfpga_arch --verbose
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml

View File

@ -0,0 +1,14 @@
#ifndef LB_RR_GRPAH_TYPES_H
#define LB_RR_GRPAH_TYPES_H
/* Describes different types of intra-logic cluster_ctx.blocks routing resource nodes */
enum e_lb_rr_type {
LB_SOURCE = 0,
LB_SINK,
LB_INTERMEDIATE,
NUM_LB_RR_TYPES
};
const std::vector<const char*> lb_rr_type_str{
"LB_SOURCE", "LB_SINK", "LB_INTERMEDIATE", "INVALID"};
#endif

View File

@ -13,20 +13,12 @@
#include "arch_types.h"
#include "atom_netlist_fwd.h"
#include "lb_rr_graph_types.h"
/**************************************************************************
* Packing Algorithm Enumerations
***************************************************************************/
/* Describes different types of intra-logic cluster_ctx.blocks routing resource nodes */
enum e_lb_rr_type {
LB_SOURCE = 0,
LB_SINK,
LB_INTERMEDIATE,
NUM_LB_RR_TYPES
};
const std::vector<const char*> lb_rr_type_str{
"LB_SOURCE", "LB_SINK", "LB_INTERMEDIATE", "INVALID"};
/**************************************************************************
* Packing Algorithm Data Structures
***************************************************************************/