Merge pull request #52 from antmicro/get_clocks Add -of switch and -include_generated_clocks to get_clocks command
diff --git a/sdc-plugin/sdc.cc b/sdc-plugin/sdc.cc index 880eeb2..a9b7f6a 100644 --- a/sdc-plugin/sdc.cc +++ b/sdc-plugin/sdc.cc
@@ -21,10 +21,10 @@ #include "kernel/register.h" #include "kernel/rtlil.h" #include "propagation.h" +#include "sdc_writer.h" +#include "set_clock_groups.h" #include "set_false_path.h" #include "set_max_delay.h" -#include "set_clock_groups.h" -#include "sdc_writer.h" USING_YOSYS_NAMESPACE @@ -73,7 +73,8 @@ } void execute(std::ostream*& f, std::string filename, - std::vector<std::string> args, RTLIL::Design* design) override { + std::vector<std::string> args, + RTLIL::Design* design) override { if (args.size() < 2) { log_cmd_error("Missing output file.\n"); } @@ -86,8 +87,7 @@ }; struct CreateClockCmd : public Pass { - CreateClockCmd() - : Pass("create_clock", "Create clock object") {} + CreateClockCmd() : Pass("create_clock", "Create clock object") {} void help() override { log("\n"); @@ -169,8 +169,7 @@ rising_edge = 0; falling_edge = period / 2; } - Clock::Add(name, selected_wires, period, rising_edge, - falling_edge); + Clock::Add(name, selected_wires, period, rising_edge, falling_edge); } void AddWirePrefix(std::vector<std::string>& args, size_t argidx) { @@ -181,29 +180,104 @@ }; struct GetClocksCmd : public Pass { - GetClocksCmd() - : Pass("get_clocks", "Create clock object") {} + GetClocksCmd() : Pass("get_clocks", "Create clock object") {} void help() override { log("\n"); - log(" get_clocks\n"); + log(" get_clocks [-include_generated_clocks] [-of <nets>] " + "[<patterns>]\n"); log("\n"); log("Returns all clocks in the design.\n"); log("\n"); + log(" -include_generated_clocks\n"); + log(" Include auto-generated clocks.\n"); + log("\n"); + log(" -of\n"); + log(" Get clocks of these nets.\n"); + log("\n"); + log(" <pattern>\n"); + log(" Pattern of clock names. Default are all clocks in the " + "design.\n"); + log("\n"); + } + + std::vector<std::string> extract_list(const std::string& args) { + std::vector<std::string> port_list; + std::stringstream ss(args); + std::istream_iterator<std::string> begin(ss); + std::istream_iterator<std::string> end; + std::copy(begin, end, std::back_inserter(port_list)); + return port_list; + } + + // TODO Check for GENERATED_CLOCK clock wire attribute + // Issue https://github.com/SymbiFlow/yosys-symbiflow-plugins/issues/53 + // For now don't treat any of the added clocks as auto-generated + bool IsGeneratedClock(RTLIL::Wire* clock_wire) { + (void)clock_wire; + return false; } void execute(std::vector<std::string> args, RTLIL::Design* design) override { - if (args.size() > 1) { - log_warning("Command doesn't support arguments, so they will be ignored.\n"); + + // Parse command arguments + bool generated_clocks(false); + std::vector<std::string> clocks_nets; + size_t argidx(0); + + // Parse command switches + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-include_generated_clocks") { + generated_clocks = true; + continue; + } + if (arg == "-of" and argidx + 1 < args.size()) { + clocks_nets = extract_list(args[++argidx]); +#ifdef SDC_DEBUG + for (auto clock_net : clocks_nets) { + log("Clock filter %s\n", clock_net.c_str()); + } +#endif + continue; + } + if (arg.size() > 0 and arg[0] == '-') { + log_cmd_error("Unknown option %s.\n", arg.c_str()); + } + + break; } + + // Parse object patterns + std::vector<std::string> clocks_list(args.begin() + argidx, args.end()); + + // Fetch clocks in the design std::map<std::string, RTLIL::Wire*> clocks(Clocks::GetClocks(design)); if (clocks.size() == 0) { log_warning("No clocks found in design\n"); } + + // Extract clocks into tcl list Tcl_Interp* interp = yosys_get_tcl_interp(); Tcl_Obj* tcl_list = Tcl_NewListObj(0, NULL); for (auto& clock : clocks) { + // Skip generated clocks if -include_generated_clocks is not specified + if (IsGeneratedClock(clock.second) and !generated_clocks) { + continue; + } + // Check if clock name is in the list of design clocks + if (clocks_list.size() > 0 and + std::find(clocks_list.begin(), clocks_list.end(), + clock.first) == clocks_list.end()) { + continue; + } + // Check if clock wire is in the -of list + if (clocks_nets.size() > 0 and + std::find(clocks_nets.begin(), clocks_nets.end(), + Clock::WireName(clock.second)) == clocks_nets.end()) { + continue; + } auto& wire = clock.second; const char* name = RTLIL::id2cstr(wire->name); Tcl_Obj* name_obj = Tcl_NewStringObj(name, -1); @@ -228,15 +302,15 @@ void execute(std::vector<std::string> args, RTLIL::Design* design) override { if (args.size() > 1) { - log_warning("Command accepts no arguments.\nAll will be ignored.\n"); + log_warning( + "Command accepts no arguments.\nAll will be ignored.\n"); } if (!design->top_module()) { log_cmd_error("No top module selected\n"); } std::array<std::unique_ptr<Propagation>, 2> passes{ - std::unique_ptr<Propagation>( - new BufferPropagation(design, this)), + std::unique_ptr<Propagation>(new BufferPropagation(design, this)), std::unique_ptr<Propagation>( new ClockDividerPropagation(design, this))};
diff --git a/sdc-plugin/tests/Makefile b/sdc-plugin/tests/Makefile index 3d602b7..8604f82 100644 --- a/sdc-plugin/tests/Makefile +++ b/sdc-plugin/tests/Makefile
@@ -19,7 +19,8 @@ restore_from_json \ period_check \ waveform_check \ - period_format_check + period_format_check \ + get_clocks UNIT_TESTS = escaping @@ -41,3 +42,4 @@ waveform_check_negative = 1 period_format_check_verify = true period_format_check_negative = 1 +get_clocks_verify = $(call diff_test,get_clocks,txt)
diff --git a/sdc-plugin/tests/get_clocks/get_clocks.golden.txt b/sdc-plugin/tests/get_clocks/get_clocks.golden.txt new file mode 100644 index 0000000..9c70eed --- /dev/null +++ b/sdc-plugin/tests/get_clocks/get_clocks.golden.txt
@@ -0,0 +1,6 @@ +{$auto$clkbufmap.cc:247:execute$1913} {$auto$clkbufmap.cc:247:execute$1915} clk clk2 clk_int_1 middle_inst_1.clk_int middle_inst_4.clk +{$auto$clkbufmap.cc:247:execute$1913} {$auto$clkbufmap.cc:247:execute$1915} clk clk2 clk_int_1 middle_inst_1.clk_int middle_inst_4.clk +clk2 +clk_int_1 +clk clk2 clk_int_1 middle_inst_1.clk_int middle_inst_4.clk +clk clk2 clk_int_1
diff --git a/sdc-plugin/tests/get_clocks/get_clocks.input.sdc b/sdc-plugin/tests/get_clocks/get_clocks.input.sdc new file mode 100644 index 0000000..01debad --- /dev/null +++ b/sdc-plugin/tests/get_clocks/get_clocks.input.sdc
@@ -0,0 +1,2 @@ +create_clock -period 10.0 -waveform {0.000 5.000} clk_int_1 +create_clock -period 10.0 -name clk -waveform {0.000 5.000} clk clk2
diff --git a/sdc-plugin/tests/get_clocks/get_clocks.tcl b/sdc-plugin/tests/get_clocks/get_clocks.tcl new file mode 100644 index 0000000..6f0eea7 --- /dev/null +++ b/sdc-plugin/tests/get_clocks/get_clocks.tcl
@@ -0,0 +1,36 @@ +yosys -import +plugin -i sdc +plugin -i design_introspection +# Import the commands from the plugins to the tcl interpreter +yosys -import + +read_verilog $::env(DESIGN_TOP).v +read_verilog -specify -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v +read_verilog -lib +/xilinx/cells_xtra.v +hierarchy -check -auto-top +# Start flow after library reading +synth_xilinx -flatten -abc9 -nosrl -nodsp -iopad -run prepare:check +#synth_xilinx + +# Read the design's timing constraints +read_sdc $::env(DESIGN_TOP).input.sdc + +# Propagate the clocks +propagate_clocks + +# Write the clocks to file +set fh [open $::env(DESIGN_TOP).txt w] + +puts $fh [get_clocks] + +puts $fh [get_clocks -include_generated_clocks] + +puts $fh [get_clocks -include_generated_clocks clk2] + +puts $fh [get_clocks -of [get_nets clk_int_1 clk1] -include_generated_clocks clk_int_1] + +puts $fh [get_clocks -of [get_nets]] + +puts $fh [get_clocks -of [concat [get_nets clk2] [get_nets clk_int_1 clk]]] + +close $fh
diff --git a/sdc-plugin/tests/get_clocks/get_clocks.v b/sdc-plugin/tests/get_clocks/get_clocks.v new file mode 100644 index 0000000..59531d2 --- /dev/null +++ b/sdc-plugin/tests/get_clocks/get_clocks.v
@@ -0,0 +1,35 @@ +module top(input clk, + input clk2, + input [1:0] in, + output [5:0] out ); + +reg [1:0] cnt = 0; +wire clk_int_1, clk_int_2; +IBUF ibuf_inst(.I(clk), .O(ibuf_out)); +assign clk_int_1 = ibuf_out; +assign clk_int_2 = clk_int_1; + +always @(posedge clk_int_2) begin + cnt <= cnt + 1; +end + +middle middle_inst_1(.clk(ibuf_out), .out(out[2])); +middle middle_inst_2(.clk(clk_int_1), .out(out[3])); +middle middle_inst_3(.clk(clk_int_2), .out(out[4])); +middle middle_inst_4(.clk(clk2), .out(out[5])); + +assign out[1:0] = {cnt[0], in[0]}; +endmodule + +module middle(input clk, + output out); + +reg [1:0] cnt = 0; +wire clk_int; +assign clk_int = clk; +always @(posedge clk_int) begin + cnt <= cnt + 1; +end + +assign out = cnt[0]; +endmodule