[core] now clock routing for programmable clock network works for 1 clock design

This commit is contained in:
tangxifan 2023-03-07 13:13:25 -08:00
parent 7e3b656c51
commit 50e201feeb
4 changed files with 146 additions and 8 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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));
}

View File

@ -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");