Merge branch 'refactoring' into dev
This commit is contained in:
commit
098f7dddf3
|
@ -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*/
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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!
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
***************************************************************************/
|
||||
|
|
Loading…
Reference in New Issue