diff --git a/openfpga/src/annotation/annotate_bitstream_setting.cpp b/openfpga/src/annotation/annotate_bitstream_setting.cpp index 5a8232734..878c8dccb 100644 --- a/openfpga/src/annotation/annotate_bitstream_setting.cpp +++ b/openfpga/src/annotation/annotate_bitstream_setting.cpp @@ -211,6 +211,56 @@ static int annotate_bitstream_default_mode_setting( return CMD_EXEC_SUCCESS; } +/******************************************************************** + * Annotate bitstream setting based on programmable clock network + * - Find the clock tree which is defined in the bitstream setting. Apply sanity check if it does not work + * - Mark id of the pin of clock tree to be routed and check if the one defined in bitstream setting is valid + *******************************************************************/ +static int annotate_bitstream_clock_routing_setting( + const BitstreamSetting& bitstream_setting, + const ClockNetwork& clk_ntwk, + VprBitstreamAnnotation& vpr_bitstream_annotation) { + /* For an empty clock network, throw warning that nothing will be done */ + if (clk_ntwk.empty() && !bitstream_setting.clock_routing_settings().empty()) { + VTR_LOG_WARN("Clock network is empty. No bitstream settings related to clock routing will be applied!\n"); + return CMD_EXEC_SUCCESS; + } + for (const auto& bitstream_clock_routing_setting_id : + bitstream_setting.clock_routing_settings()) { + /* Validate if the given clock network name is valid */ + std::string ntwk_name = bitstream_setting.clock_routing_network(bitstream_clock_routing_setting_id); + ClockTreeId tree_id = clk_ntwk.find_tree(ntwk_name); + if (!clk_ntwk.valid_tree_id(tree_id)) { + VTR_LOG_ERROR("Invalid clock network name '%s' from bitstream setting, which is not defined in the clock network description!\n", ntwk_name.c_str()); + /* Show valid clock network names */ + VTR_LOG("Valid clock network names are as follows\n"); + for (auto curr_tree_id : clk_ntwk.trees()) { + VTR_LOG("\t%s\n", clk_ntwk.tree_name(curr_tree_id).c_str()); + } + return CMD_EXEC_FATAL_ERROR; + } + /* Valid the port */ + BasicPort tree_port = clk_ntwk.tree_global_port(tree_id); + BasicPort wanted_pin = bitstream_setting.clock_routing_pin(bitstream_clock_routing_setting_id); + if (wanted_pin.get_width() != 1) { + VTR_LOG_ERROR("Invalid clock pin definition '%s' from bitstream setting for clock network name '%s', whose port width must be 1!\n", wanted_pin.to_verilog_string().c_str(), ntwk_name.c_str()); + return CMD_EXEC_FATAL_ERROR; + } + if (!tree_port.mergeable(wanted_pin)) { + VTR_LOG_ERROR("Invalid clock pin definition '%s' from bitstream setting for clock network name '%s', which does not match the name of pin '%s' in the clock network description!\n", wanted_pin.to_verilog_string().c_str(), ntwk_name.c_str(), tree_port.to_verilog_string.c_str()); + return CMD_EXEC_FATAL_ERROR; + } + if (!tree_port.contained(wanted_pin) { + VTR_LOG_ERROR("Invalid clock pin definition '%s' from bitstream setting for clock network name '%s', which is out of the pin '%s' in the clock network description!\n", wanted_pin.to_verilog_string().c_str(), ntwk_name.c_str(), tree_port.to_verilog_string.c_str()); + return CMD_EXEC_FATAL_ERROR; + } + /* All sanity check passed. Record the bitstream requirements */ + ClockTreePinId tree_pin_id = clk_ntwk.pins(tree_id)[tree_port.find_ipin(wanted_pin)]; + vpr_bitstream_annotation.set_clock_tap_routing_pin(tree_id, tree_pin_id); + } + return CMD_EXEC_SUCCESS; +} + /******************************************************************** * Annotate bitstream setting based on VPR device information * - Find the interconnect and link to the default path id @@ -352,6 +402,12 @@ int annotate_bitstream_setting( return status; } + status = annotate_bitstream_clock_routing_setting(bitstream_setting, vpr_device_ctx, + vpr_bitstream_annotation); + if (status == CMD_EXEC_FATAL_ERROR) { + return status; + } + status = annotate_bitstream_default_mode_setting( bitstream_setting, vpr_device_ctx, vpr_device_annotation); if (status == CMD_EXEC_FATAL_ERROR) { diff --git a/openfpga/src/annotation/vpr_bitstream_annotation.cpp b/openfpga/src/annotation/vpr_bitstream_annotation.cpp index 000b9c687..424289961 100644 --- a/openfpga/src/annotation/vpr_bitstream_annotation.cpp +++ b/openfpga/src/annotation/vpr_bitstream_annotation.cpp @@ -107,6 +107,18 @@ size_t VprBitstreamAnnotation::interconnect_default_path_id( return DEFAULT_PATH_ID; } +ClockTreePinId VprBitstreamAnnotation::clock_tap_routing_pin( + const ClockTreeId& tree_id) const { + auto result = clock_tap_routing_pins_.find(tree_id); + if (result != clock_tap_routing_pins_.end()) { + return result->second; + } + + /* Not found, return an invalid input id */ + return ClockTreePinId::INVALID(); +} + + /************************************************************************ * Public mutators ***********************************************************************/ @@ -150,4 +162,14 @@ void VprBitstreamAnnotation::set_interconnect_default_path_id( interconnect_default_path_ids_[interconnect] = default_path_id; } +void VprBitstreamAnnotation::set_clock_tap_routing_pin( + const ClockTreeId& tree_id, const ClockTreePinId& tree_pin_id) { + auto result = clock_tap_routing_pins_.find(tree_id); + if (result != clock_tap_routing_pins_.end()) { + VTR_LOG_WARN("Overwrite the clock tree pin '%lu' for clock tree '%d' tap routing (Was pin '%lu')\n", + size_t(tree_pin_id), size_t(tree_id), size_t(result->second)); + } + clock_tap_routing_pins_[tree_id] = tree_pin_id; +} + } /* End namespace openfpga*/ diff --git a/openfpga/src/annotation/vpr_bitstream_annotation.h b/openfpga/src/annotation/vpr_bitstream_annotation.h index 3ddb330c0..caa0b213a 100644 --- a/openfpga/src/annotation/vpr_bitstream_annotation.h +++ b/openfpga/src/annotation/vpr_bitstream_annotation.h @@ -9,6 +9,7 @@ /* Header from vpr library */ #include "vpr_context.h" +#include "clock_network.h" /* Begin namespace openfpga */ namespace openfpga { @@ -43,6 +44,7 @@ class VprBitstreamAnnotation { std::string pb_type_mode_select_bitstream_content(t_pb_type* pb_type) const; size_t pb_type_mode_select_bitstream_offset(t_pb_type* pb_type) const; size_t interconnect_default_path_id(t_interconnect* interconnect) const; + ClockTreePinId clock_tap_routing_pin(const ClockTreeId& tree_id) const; public: /* Public mutators */ void set_pb_type_bitstream_source( @@ -62,6 +64,7 @@ class VprBitstreamAnnotation { const size_t& offset); void set_interconnect_default_path_id(t_interconnect* interconnect, const size_t& default_path_id); + void set_clock_tap_routing_pin(const ClockTreeId& tree_id, const ClockTreePinId& tree_pin_id); private: /* Internal data */ /* For regular bitstreams */ @@ -87,6 +90,11 @@ class VprBitstreamAnnotation { * the index of inputs in the context of the interconnect input string */ std::map interconnect_default_path_ids_; + + /* Mark the clock tree pin for which all the tap points of clock tree should be routed through + * Note that for each clock tree, only one pin is allowed + */ + std::map clock_tap_routing_pins_; }; } /* End namespace openfpga*/