[core] now clock routing for programmable clock network works for 1 clock design
This commit is contained in:
parent
7e3b656c51
commit
50e201feeb
|
@ -1,6 +1,7 @@
|
|||
#include "route_clock_rr_graph.h"
|
||||
|
||||
#include "command_exit_codes.h"
|
||||
#include "openfpga_atom_netlist_utils.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_geometry.h"
|
||||
#include "vtr_log.h"
|
||||
|
@ -9,6 +10,73 @@
|
|||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Build the lookup between clock name and pins and clock tree pins
|
||||
* This is required for routing clock nets in each clock tree
|
||||
* Special: when there is only 1 clock and 1 clock tree (width = 1), the mapping
|
||||
*is straight forward
|
||||
* FIXME: This part works only for clock network which constains only 1 clock
|
||||
*tree!
|
||||
*******************************************************************/
|
||||
static int build_clock_tree_net_map(
|
||||
std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
||||
const ClusteredNetlist& cluster_nlist, const PinConstraints& pin_constraints,
|
||||
const std::vector<std::string>& clk_names, const ClockNetwork& clk_ntwk,
|
||||
const ClockTreeId clk_tree, const bool& verbose) {
|
||||
/* Find the pin id for each clock name, error out if there is any mismatch */
|
||||
if (clk_names.size() == 1 && clk_ntwk.tree_width(clk_tree) == 1) {
|
||||
/* Find cluster net id */
|
||||
ClusterNetId clk_net = cluster_nlist.find_net(clk_names[0]);
|
||||
if (!cluster_nlist.valid_net_id(clk_net)) {
|
||||
VTR_LOG_ERROR("Invalid clock name '%s'! Cannot found from netlists!\n",
|
||||
clk_names[0].c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
tree2clk_pin_map[ClockTreePinId(0)] = clk_net;
|
||||
} else {
|
||||
for (std::string clk_name : clk_names) {
|
||||
/* Find the pin information that the net should be mapped to */
|
||||
BasicPort tree_pin = pin_constraints.net_pin(clk_name);
|
||||
if (!tree_pin.is_valid()) {
|
||||
VTR_LOG_ERROR(
|
||||
"Invalid tree pin for clock '%s'! Clock name may not be valid "
|
||||
"(mismatched with netlists)!\n",
|
||||
clk_name.c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
if (tree_pin.get_width() != 1) {
|
||||
VTR_LOG_ERROR(
|
||||
"Invalid tree pin %s[%lu:%lu] for clock '%s'! Clock pin must have "
|
||||
"only a width of 1!\n",
|
||||
tree_pin.get_name().c_str(), tree_pin.get_lsb(), tree_pin.get_msb(),
|
||||
clk_name.c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
if (tree_pin.get_lsb() >= clk_ntwk.tree_width(clk_tree)) {
|
||||
VTR_LOG_ERROR(
|
||||
"Invalid tree pin %s[%lu] is out of range of clock tree size '%lu'\n",
|
||||
tree_pin.get_name().c_str(), tree_pin.get_lsb(),
|
||||
clk_ntwk.tree_width(clk_tree));
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
/* Find cluster net id */
|
||||
ClusterNetId clk_net = cluster_nlist.find_net(clk_name);
|
||||
if (!cluster_nlist.valid_net_id(clk_net)) {
|
||||
VTR_LOG_ERROR("Invalid clock name '%s'! Cannot found from netlists!\n",
|
||||
clk_name.c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
/* Register the pin mapping */
|
||||
tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = clk_net;
|
||||
}
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose, "Build a pin map for %lu clock nets and pins.\n",
|
||||
tree2clk_pin_map.size());
|
||||
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Route a clock tree on an existing routing resource graph
|
||||
* The strategy is to route spine one by one
|
||||
|
@ -18,8 +86,10 @@ namespace openfpga {
|
|||
*******************************************************************/
|
||||
static int route_clock_tree_rr_graph(
|
||||
VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph,
|
||||
const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk,
|
||||
const ClockTreeId clk_tree, const bool& verbose) {
|
||||
const RRClockSpatialLookup& clk_rr_lookup,
|
||||
const std::map<ClockTreePinId, ClusterNetId>& tree2clk_pin_map,
|
||||
const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree,
|
||||
const bool& verbose) {
|
||||
for (auto ispine : clk_ntwk.spines(clk_tree)) {
|
||||
VTR_LOGV(verbose, "Routing spine '%s'...\n",
|
||||
clk_ntwk.spine_name(ispine).c_str());
|
||||
|
@ -71,6 +141,10 @@ static int route_clock_tree_rr_graph(
|
|||
VTR_ASSERT(rr_graph.valid_node(des_node));
|
||||
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node,
|
||||
src_node);
|
||||
vpr_routing_annotation.set_rr_node_net(src_node,
|
||||
tree2clk_pin_map.at(ipin));
|
||||
vpr_routing_annotation.set_rr_node_net(des_node,
|
||||
tree2clk_pin_map.at(ipin));
|
||||
}
|
||||
/* Route the spine-to-IPIN connections (only for the last level) */
|
||||
if (clk_ntwk.is_last_level(ispine)) {
|
||||
|
@ -91,6 +165,10 @@ static int route_clock_tree_rr_graph(
|
|||
VTR_ASSERT(rr_graph.valid_node(des_node));
|
||||
vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node,
|
||||
src_node);
|
||||
vpr_routing_annotation.set_rr_node_net(src_node,
|
||||
tree2clk_pin_map.at(ipin));
|
||||
vpr_routing_annotation.set_rr_node_net(des_node,
|
||||
tree2clk_pin_map.at(ipin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,8 +186,13 @@ static int route_clock_tree_rr_graph(
|
|||
*******************************************************************/
|
||||
int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
const AtomContext& atom_ctx,
|
||||
const ClusteredNetlist& cluster_nlist,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const RRClockSpatialLookup& clk_rr_lookup,
|
||||
const ClockNetwork& clk_ntwk, const bool& verbose) {
|
||||
const ClockNetwork& clk_ntwk,
|
||||
const PinConstraints& pin_constraints,
|
||||
const bool& verbose) {
|
||||
vtr::ScopedStartFinishTimer timer(
|
||||
"Route programmable clock network based on routing resource graph");
|
||||
|
||||
|
@ -129,13 +212,42 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation,
|
|||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* If there are multiple clock signals from the netlist, require pin
|
||||
* constraints */
|
||||
std::vector<std::string> clock_net_names =
|
||||
find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
|
||||
if (clock_net_names.empty()) {
|
||||
VTR_LOG(
|
||||
"Skip due to 0 clocks found from netlist\nDouble check your HDL design "
|
||||
"if this is unexpected\n");
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
if (clock_net_names.size() > 1 && pin_constraints.empty()) {
|
||||
VTR_LOG(
|
||||
"There is %lu clock nets (more than 1). Require pin constraints to be "
|
||||
"specified\n",
|
||||
clock_net_names.size());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Route spines one by one */
|
||||
for (auto itree : clk_ntwk.trees()) {
|
||||
VTR_LOGV(verbose, "Build clock name to clock tree '%s' pin mapping...\n",
|
||||
clk_ntwk.tree_name(itree).c_str());
|
||||
std::map<ClockTreePinId, ClusterNetId> tree2clk_pin_map;
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
status =
|
||||
build_clock_tree_net_map(tree2clk_pin_map, cluster_nlist, pin_constraints,
|
||||
clock_net_names, clk_ntwk, itree, verbose);
|
||||
if (status == CMD_EXEC_FATAL_ERROR) {
|
||||
return status;
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose, "Routing clock tree '%s'...\n",
|
||||
clk_ntwk.tree_name(itree).c_str());
|
||||
int status =
|
||||
route_clock_tree_rr_graph(vpr_routing_annotation, vpr_device_ctx.rr_graph,
|
||||
clk_rr_lookup, clk_ntwk, itree, verbose);
|
||||
status = route_clock_tree_rr_graph(
|
||||
vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup,
|
||||
tree2clk_pin_map, clk_ntwk, itree, verbose);
|
||||
if (status == CMD_EXEC_FATAL_ERROR) {
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "clock_network.h"
|
||||
#include "pin_constraints.h"
|
||||
#include "rr_clock_spatial_lookup.h"
|
||||
#include "vpr_context.h"
|
||||
#include "vpr_netlist_annotation.h"
|
||||
#include "vpr_routing_annotation.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -18,8 +20,13 @@ namespace openfpga {
|
|||
|
||||
int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
const AtomContext& atom_ctx,
|
||||
const ClusteredNetlist& cluster_nlist,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const RRClockSpatialLookup& clk_rr_lookup,
|
||||
const ClockNetwork& clk_ntwk, const bool& verbose);
|
||||
const ClockNetwork& clk_ntwk,
|
||||
const PinConstraints& pin_constraints,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "openfpga_rr_graph_support.h"
|
||||
#include "pb_type_utils.h"
|
||||
#include "read_activity.h"
|
||||
#include "read_xml_pin_constraints.h"
|
||||
#include "route_clock_rr_graph.h"
|
||||
#include "vpr_device_annotation.h"
|
||||
#include "vtr_assert.h"
|
||||
|
@ -214,11 +215,22 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd,
|
|||
const CommandContext& cmd_context) {
|
||||
vtr::ScopedStartFinishTimer timer("Route clock routing resource graph");
|
||||
|
||||
/* add an option '--pin_constraints_file in short '-pcf' */
|
||||
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
|
||||
CommandOptionId opt_verbose = cmd.option("verbose");
|
||||
|
||||
/* If pin constraints are enabled by command options, read the file */
|
||||
PinConstraints pin_constraints;
|
||||
if (true == cmd_context.option_enable(cmd, opt_pcf)) {
|
||||
pin_constraints =
|
||||
read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str());
|
||||
}
|
||||
|
||||
return route_clock_rr_graph(
|
||||
openfpga_ctx.mutable_vpr_routing_annotation(), g_vpr_ctx.device(),
|
||||
openfpga_ctx.clock_rr_lookup(), openfpga_ctx.clock_arch(),
|
||||
g_vpr_ctx.atom(), g_vpr_ctx.clustering().clb_nlist,
|
||||
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.clock_rr_lookup(),
|
||||
openfpga_ctx.clock_arch(), pin_constraints,
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
}
|
||||
|
||||
|
|
|
@ -667,6 +667,13 @@ ShellCommandId add_route_clock_rr_graph_command_template(
|
|||
const std::vector<ShellCommandId>& dependent_cmds, const bool& hidden) {
|
||||
Command shell_cmd("route_clock_rr_graph");
|
||||
|
||||
/* Add an option '--file' in short '-f'*/
|
||||
CommandOptionId opt_file =
|
||||
shell_cmd.add_option("pin_constraints_file", false,
|
||||
"specify the file path to the pin constraints");
|
||||
shell_cmd.set_option_short_name(opt_file, "pcf");
|
||||
shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--verbose' */
|
||||
shell_cmd.add_option("verbose", false, "Show verbose outputs");
|
||||
|
||||
|
|
Loading…
Reference in New Issue