Merge pull request #57 from antmicro/sdc_skip_clocks_on_dangling_wires

SDC: Skip adding clocks on dangling wires
diff --git a/sdc-plugin/propagation.cc b/sdc-plugin/propagation.cc
index a2dffe2..f7e59d8 100644
--- a/sdc-plugin/propagation.cc
+++ b/sdc-plugin/propagation.cc
@@ -114,6 +114,22 @@
     return sink_cell;
 }
 
+bool Propagation::WireHasSinkCell(RTLIL::Wire* wire) {
+    if (!wire) {
+	return false;
+    }
+    RTLIL::Module* top_module = design_->top_module();
+    assert(top_module);
+    std::string base_selection =
+        top_module->name.str() + "/w:" + wire->name.str();
+    pass_->extra_args(
+        std::vector<std::string>{base_selection, "%co:*",
+                                 base_selection, "%d"},
+        0, design_);
+    auto selected_cells = top_module->selected_cells();
+    return selected_cells.size() > 0;
+}
+
 RTLIL::Wire* Propagation::FindSinkWireOnPort(RTLIL::Cell* cell,
                                              const std::string& port_name) {
     RTLIL::Wire* sink_wire = NULL;
@@ -140,6 +156,7 @@
     }
     return sink_wire;
 }
+
 void NaturalPropagation::Run() {
 #ifdef SDC_DEBUG
     log("Start natural clock propagation\n");
@@ -230,7 +247,8 @@
 	        Clock::RisingEdge(driver_wire));
 	for (auto output : Pll::outputs) {
 	    RTLIL::Wire* wire = FindSinkWireOnPort(cell, output);
-	    if (wire) {
+	    // Don't add clocks on dangling wires
+	    if (wire && WireHasSinkCell(wire)) {
 		float clkout_period(pll.clkout_period.at(output));
 		float clkout_rising_edge(pll.clkout_rising_edge.at(output));
 		float clkout_falling_edge(pll.clkout_falling_edge.at(output));
diff --git a/sdc-plugin/propagation.h b/sdc-plugin/propagation.h
index 788b138..29ee07f 100644
--- a/sdc-plugin/propagation.h
+++ b/sdc-plugin/propagation.h
@@ -42,6 +42,7 @@
     RTLIL::Cell* FindSinkCellOnPort(RTLIL::Wire* wire, const std::string& port);
     RTLIL::Wire* FindSinkWireOnPort(RTLIL::Cell* cell,
                                     const std::string& port_name);
+    bool WireHasSinkCell(RTLIL::Wire* wire);
 };
 
 class NaturalPropagation : public Propagation {
diff --git a/sdc-plugin/tests/Makefile b/sdc-plugin/tests/Makefile
index 8604f82..56525df 100644
--- a/sdc-plugin/tests/Makefile
+++ b/sdc-plugin/tests/Makefile
@@ -13,6 +13,7 @@
 	pll_div \
 	pll_fbout_phase \
 	pll_approx_equal \
+	pll_dangling_wires \
 	set_false_path \
 	set_max_delay \
 	set_clock_groups \
@@ -32,6 +33,7 @@
 pll_div_verify = $(call diff_test,pll_div,sdc)
 pll_fbout_phase_verify = $(call diff_test,pll_fbout_phase,sdc)
 pll_approx_equal_verify = $(call diff_test,pll_approx_equal,sdc)
+pll_dangling_wires_verify = $(call diff_test,pll_dangling_wires,sdc)
 set_false_path_verify = $(call diff_test,set_false_path,sdc)
 set_max_delay_verify = $(call diff_test,set_max_delay,sdc)
 set_clock_groups_verify = $(call diff_test,set_clock_groups,sdc)
diff --git a/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.golden.sdc b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.golden.sdc
new file mode 100644
index 0000000..b2269fe
--- /dev/null
+++ b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.golden.sdc
@@ -0,0 +1,3 @@
+create_clock -period 10 -waveform {0 5} \$abc\$1699\$iopadmap\$clk
+create_clock -period 10 -waveform {0 5} \$auto\$clkbufmap.cc:262:execute\$1704
+create_clock -period 10 -waveform {0 5} main_clkout0
diff --git a/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.input.sdc b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.input.sdc
new file mode 100644
index 0000000..00354d7
--- /dev/null
+++ b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.input.sdc
@@ -0,0 +1 @@
+create_clock -period 10 -waveform {0 5} clk
diff --git a/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.tcl b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.tcl
new file mode 100644
index 0000000..09973b8
--- /dev/null
+++ b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.tcl
@@ -0,0 +1,21 @@
+yosys -import
+plugin -i sdc
+# 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
+
+# Read the design timing constraints
+read_sdc $::env(DESIGN_TOP).input.sdc
+
+# Propagate the clocks
+propagate_clocks
+
+# Write out the SDC file after the clock propagation step
+write_sdc $::env(DESIGN_TOP).sdc
diff --git a/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.v b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.v
new file mode 100644
index 0000000..826483f
--- /dev/null
+++ b/sdc-plugin/tests/pll_dangling_wires/pll_dangling_wires.v
@@ -0,0 +1,41 @@
+module top(
+	input clk,
+	input cpu_reset,
+	input data_in,
+	output data_out
+);
+
+wire data_out;
+wire builder_pll_fb;
+wire main_locked;
+
+PLLE2_ADV #(
+	.CLKFBOUT_MULT(4'd12),
+	.CLKIN1_PERIOD(10.0),
+	.CLKOUT0_DIVIDE(4'd12),
+	.CLKOUT0_PHASE(0.0),
+	.DIVCLK_DIVIDE(1'd1),
+	.REF_JITTER1(0.01),
+	.STARTUP_WAIT("FALSE")
+) PLLE2_ADV (
+	.CLKFBIN(builder_pll_fb),
+	.CLKIN1(clk),
+	.RST(cpu_reset),
+	.CLKFBOUT(builder_pll_fb),
+	.CLKOUT0(main_clkout0),
+	.CLKOUT1(main_clkout1),
+	.CLKOUT2(main_clkout2),
+	.CLKOUT3(main_clkout3),
+	.CLKOUT4(main_clkout4),
+	.LOCKED(main_locked)
+);
+
+FDCE FDCE_PLLx1_PH0 (
+	.D(data_in),
+	.C(main_clkout0),
+	.CE(1'b1),
+	.CLR(1'b0),
+	.Q(data_out)
+);
+
+endmodule