SDC: Add set_clock_groups command and adjust SDC Writer Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/sdc-plugin/Makefile b/sdc-plugin/Makefile index 68b0917..f45efdc 100644 --- a/sdc-plugin/Makefile +++ b/sdc-plugin/Makefile
@@ -1,3 +1,10 @@ NAME = sdc -SOURCES = buffers.cc clocks.cc propagation.cc sdc.cc sdc_writer.cc set_false_path.cc set_max_delay.cc +SOURCES = buffers.cc \ + clocks.cc \ + propagation.cc \ + sdc.cc \ + sdc_writer.cc \ + set_false_path.cc \ + set_max_delay.cc \ + set_clock_groups.cc include ../Makefile_plugin.common
diff --git a/sdc-plugin/sdc.cc b/sdc-plugin/sdc.cc index df09526..c138b04 100644 --- a/sdc-plugin/sdc.cc +++ b/sdc-plugin/sdc.cc
@@ -23,6 +23,7 @@ #include "propagation.h" #include "set_false_path.h" #include "set_max_delay.h" +#include "set_clock_groups.h" #include "sdc_writer.h" USING_YOSYS_NAMESPACE @@ -255,7 +256,8 @@ get_clocks_cmd_(clocks_), propagate_clocks_cmd_(clocks_), set_false_path_cmd_(sdc_writer_), - set_max_delay_cmd_(sdc_writer_) { + set_max_delay_cmd_(sdc_writer_), + set_clock_groups_cmd_(sdc_writer_) { log("Loaded SDC plugin\n"); } @@ -266,6 +268,7 @@ PropagateClocksCmd propagate_clocks_cmd_; SetFalsePath set_false_path_cmd_; SetMaxDelay set_max_delay_cmd_; + SetClockGroups set_clock_groups_cmd_; private: Clocks clocks_;
diff --git a/sdc-plugin/sdc_writer.cc b/sdc-plugin/sdc_writer.cc index 3c106d3..e4076f8 100644 --- a/sdc-plugin/sdc_writer.cc +++ b/sdc-plugin/sdc_writer.cc
@@ -19,6 +19,12 @@ USING_YOSYS_NAMESPACE +const std::map<ClockGroups::ClockGroupRelation, std::string> ClockGroups::relation_name_map = { + {NONE, ""}, + {ASYNCHRONOUS, "asynchronous"}, + {PHYSICALLY_EXCLUSIVE, "physically_exclusive"}, + {LOGICALLY_EXCLUSIVE, "logically_exclusive"}}; + void SdcWriter::AddFalsePath(FalsePath false_path) { false_paths_.push_back(false_path); } @@ -27,10 +33,15 @@ timing_paths_.push_back(timing_path); } +void SdcWriter::AddClockGroup(ClockGroups::ClockGroup clock_group, ClockGroups::ClockGroupRelation relation) { + clock_groups_.Add(clock_group, relation); +} + void SdcWriter::WriteSdc(Clocks& clocks, std::ostream& file) { WriteClocks(clocks, file); WriteFalsePaths(file); WriteMaxDelay(file); + WriteClockGroups(file); } void SdcWriter::WriteClocks(Clocks& clocks, std::ostream& file) { @@ -79,3 +90,23 @@ file << std::endl; } } + +void SdcWriter::WriteClockGroups(std::ostream& file) { + for (size_t relation = 0; relation <= ClockGroups::CLOCK_GROUP_RELATION_SIZE; relation++) { + auto clock_groups = clock_groups_.GetGroups(static_cast<ClockGroups::ClockGroupRelation>(relation)); + if (clock_groups.size() == 0) { + continue; + } + file << "create_clock_groups "; + for (auto group : clock_groups) { + file << "-group "; + for (auto signal : group) { + file << signal << " "; + } + } + if (relation != ClockGroups::ClockGroupRelation::NONE) { + file << "-" + ClockGroups::relation_name_map.at(static_cast<ClockGroups::ClockGroupRelation>(relation)); + } + file << std::endl; + } +}
diff --git a/sdc-plugin/sdc_writer.h b/sdc-plugin/sdc_writer.h index 5620841..05a8dea 100644 --- a/sdc-plugin/sdc_writer.h +++ b/sdc-plugin/sdc_writer.h
@@ -18,6 +18,7 @@ #ifndef _SDC_WRITER_H_ #define _SDC_WRITER_H_ #include "clocks.h" +#include <map> USING_YOSYS_NAMESPACE @@ -32,19 +33,44 @@ float max_delay; }; +struct ClockGroups { + enum ClockGroupRelation { NONE, ASYNCHRONOUS, PHYSICALLY_EXCLUSIVE, LOGICALLY_EXCLUSIVE, CLOCK_GROUP_RELATION_SIZE }; + using ClockGroup = std::vector<std::string>; + static const std::map<ClockGroupRelation, std::string> relation_name_map; + + void Add(ClockGroup& group, ClockGroupRelation relation) { + groups_[relation].push_back(group); + } + std::vector<ClockGroup> GetGroups(ClockGroupRelation relation) { + if (groups_.count(relation)) { + return groups_.at(relation); + } + return std::vector<ClockGroup>(); + } + size_t size() { + return groups_.size(); + } + + private: + std::map<ClockGroupRelation,std::vector<ClockGroup>> groups_; +}; + class SdcWriter { public: void AddFalsePath(FalsePath false_path); void SetMaxDelay(TimingPath timing_path); + void AddClockGroup(ClockGroups::ClockGroup clock_group, ClockGroups::ClockGroupRelation relation); void WriteSdc(Clocks& clocks, std::ostream& file); private: void WriteClocks(Clocks& clocks, std::ostream& file); void WriteFalsePaths(std::ostream& file); void WriteMaxDelay(std::ostream& file); + void WriteClockGroups(std::ostream& file); std::vector<FalsePath> false_paths_; std::vector<TimingPath> timing_paths_; + ClockGroups clock_groups_; }; #endif // _SDC_WRITER_H_
diff --git a/sdc-plugin/set_clock_groups.cc b/sdc-plugin/set_clock_groups.cc new file mode 100644 index 0000000..301ca96 --- /dev/null +++ b/sdc-plugin/set_clock_groups.cc
@@ -0,0 +1,116 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 The Symbiflow Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "set_clock_groups.h" +#include <regex> +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE + +void SetClockGroups::help() { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" set_clock_groups [-quiet] [-group <args>] [-asynchronous] \n"); + log("\n"); + log("Set exclusive or asynchronous clock groups\n"); + log("\n"); + log("Print the output to stdout too. This is useful when all Yosys is " + "executed.\n"); + log("\n"); + log(" -quiet\n"); + log(" Don't print the result of the execution to stdout.\n"); + log("\n"); + log(" -group\n"); + log(" List of clocks to be included in the clock group.\n"); + log("\n"); + log(" -asynchronous\n"); + log(" The specified clocks are asynchronous to each other.\n"); + log("\n"); +} + +void SetClockGroups::execute(std::vector<std::string> args, + RTLIL::Design* design) { + RTLIL::Module* top_module = design->top_module(); + if (top_module == nullptr) { + log_cmd_error("No top module detected\n"); + } + + size_t argidx; + bool is_quiet = false; + std::vector<ClockGroups::ClockGroup> clock_groups; + auto clock_groups_relation = ClockGroups::NONE; + + // Parse command arguments + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-quiet") { + is_quiet = true; + continue; + } + + // Parse clock groups relation: asynchronous, logically_exclusive, physically_exclusive + auto is_relation_arg = + [arg](std::pair<ClockGroups::ClockGroupRelation, std::string> + relation) { + if (arg.substr(1) == relation.second) { + return true; + } + return false; + }; + auto relation_map_it = + std::find_if(ClockGroups::relation_name_map.begin(), + ClockGroups::relation_name_map.end(), is_relation_arg); + if (relation_map_it != ClockGroups::relation_name_map.end()) { + clock_groups_relation = relation_map_it->first; + continue; + } + + if (arg == "-group" and argidx + 1 < args.size()) { + ClockGroups::ClockGroup clock_group; + while (argidx + 1 < args.size() and args[argidx+1][0] != '-') { + clock_group.push_back(args[++argidx]); + } + clock_groups.push_back(clock_group); + continue; + } + + if (arg.size() > 0 and arg[0] == '-') { + log_cmd_error("Unknown option %s.\n", arg.c_str()); + } + + break; + } + + if (clock_groups.size()) { + if (!is_quiet) { + std::string msg = ClockGroups::relation_name_map.at(clock_groups_relation); + msg += (!msg.empty()) ? " " : ""; + log("Adding %sclock group with following clocks:\n", msg.c_str()); + } + size_t count(0); + for (auto& group : clock_groups) { + sdc_writer_.AddClockGroup(group, clock_groups_relation); + if (!is_quiet) { + log("%zu: ", count++); + for (auto clk : group) { + log("%s ", clk.c_str()); + } + log("\n"); + } + } + } +}
diff --git a/sdc-plugin/set_clock_groups.h b/sdc-plugin/set_clock_groups.h new file mode 100644 index 0000000..3114578 --- /dev/null +++ b/sdc-plugin/set_clock_groups.h
@@ -0,0 +1,39 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 The Symbiflow Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _SET_CLOCK_GROUPS_H_ +#define _SET_CLOCK_GROUPS_H_ + +#include "kernel/register.h" +#include "kernel/rtlil.h" +#include "sdc_writer.h" + +USING_YOSYS_NAMESPACE + +struct SetClockGroups : public Pass { + SetClockGroups(SdcWriter& sdc_writer) + : Pass("set_clock_groups", "Set exclusive or asynchronous clock groups"), + sdc_writer_(sdc_writer) {} + + void help() override; + + void execute(std::vector<std::string> args, RTLIL::Design* design) override; + + SdcWriter& sdc_writer_; +}; + +#endif //_SET_CLOCK_GROUPS_H_