SDC: Move the propagation methods to Propagation class

Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/Makefile_plugin.common b/Makefile_plugin.common
index 6215cbb..4289bd6 100644
--- a/Makefile_plugin.common
+++ b/Makefile_plugin.common
@@ -37,7 +37,7 @@
 # |-- example2-plugin
 # |-- ...
 CXX = $(shell yosys-config --cxx)
-CXXFLAGS = $(shell yosys-config --cxxflags)
+CXXFLAGS = $(shell yosys-config --cxxflags) #-DSDC_DEBUG
 LDFLAGS = $(shell yosys-config --ldflags)
 LDLIBS = $(shell yosys-config --ldlibs)
 PLUGINS_DIR = $(shell yosys-config --datdir)/plugins
diff --git a/sdc-plugin/buffers.cc b/sdc-plugin/buffers.cc
index af28eaf..a48a26a 100644
--- a/sdc-plugin/buffers.cc
+++ b/sdc-plugin/buffers.cc
@@ -15,9 +15,9 @@
  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
+#include "buffers.h"
 #include <cassert>
 #include <cmath>
-#include "buffers.h"
 
 const std::vector<std::string> Pll::inputs = {"CLKIN1", "CLKIN2"};
 const std::vector<std::string> Pll::outputs = {"CLKOUT0", "CLKOUT1", "CLKOUT2",
@@ -25,9 +25,9 @@
 const float Pll::delay = 0;
 const std::string Pll::name = "PLLE2_ADV";
 
-Pll::Pll(RTLIL::Cell* cell, float input_clock_period, float input_clock_rising_edge)
- : ClockDivider({"PLLE2_ADV"})
-{
+Pll::Pll(RTLIL::Cell* cell, float input_clock_period,
+         float input_clock_rising_edge)
+    : ClockDivider({"PLLE2_ADV"}) {
     assert(RTLIL::unescape_id(cell->type) == "PLLE2_ADV");
     FetchParams(cell);
     CheckInputClockPeriod(cell, input_clock_period);
@@ -37,7 +37,9 @@
 
 void Pll::CheckInputClockPeriod(RTLIL::Cell* cell, float input_clock_period) {
     float abs_diff = fabs(ClkinPeriod() - input_clock_period);
-    bool approx_equal = abs_diff < std::max(ClkinPeriod(), input_clock_period) * 10 * std::numeric_limits<float>::epsilon();
+    bool approx_equal = abs_diff < std::max(ClkinPeriod(), input_clock_period) *
+                                       10 *
+                                       std::numeric_limits<float>::epsilon();
     if (!approx_equal) {
 	log_cmd_error(
 	    "CLKIN[1/2]_PERIOD doesn't match the virtual clock constraint "
@@ -55,7 +57,8 @@
     divclk_divisor = FetchParam(cell, "DIVCLK_DIVIDE", 1.0);
     for (auto output : outputs) {
 	// CLKOUT[0-5]_DUTY_CYCLE
-	clkout_duty_cycle[output] = FetchParam(cell, output + "_DUTY_CYCLE", 0.5);
+	clkout_duty_cycle[output] =
+	    FetchParam(cell, output + "_DUTY_CYCLE", 0.5);
 	// CLKOUT[0-5]_DIVIDE
 	clkout_divisor[output] = FetchParam(cell, output + "_DIVIDE", 1.0);
 	// CLKOUT[0-5]_PHASE
@@ -65,22 +68,30 @@
 
 void Pll::CalculateOutputClockPeriods() {
     for (auto output : outputs) {
-	// CLKOUT[0-5]_PERIOD = CLKIN1_PERIOD * CLKOUT[0-5]_DIVIDE * DIVCLK_DIVIDE /
-	// CLKFBOUT_MULT
-	clkout_period[output] = ClkinPeriod() * clkout_divisor.at(output) / clk_mult *
-	    divclk_divisor;
+	// CLKOUT[0-5]_PERIOD = CLKIN1_PERIOD * CLKOUT[0-5]_DIVIDE *
+	// DIVCLK_DIVIDE / CLKFBOUT_MULT
+	clkout_period[output] = ClkinPeriod() * clkout_divisor.at(output) /
+	                        clk_mult * divclk_divisor;
     }
 }
 
 void Pll::CalculateOutputClockWaveforms(float input_clock_rising_edge) {
     for (auto output : outputs) {
 	float output_clock_period = clkout_period.at(output);
-	clkout_rising_edge[output] = fmod(input_clock_rising_edge - (clk_fbout_phase / 360.0) * ClkinPeriod() + output_clock_period * (clkout_phase[output] / 360.0), output_clock_period);
-	clkout_falling_edge[output] = fmod(clkout_rising_edge[output] + clkout_duty_cycle[output] * output_clock_period, output_clock_period);
+	clkout_rising_edge[output] =
+	    fmod(input_clock_rising_edge -
+	             (clk_fbout_phase / 360.0) * ClkinPeriod() +
+	             output_clock_period * (clkout_phase[output] / 360.0),
+	         output_clock_period);
+	clkout_falling_edge[output] =
+	    fmod(clkout_rising_edge[output] +
+	             clkout_duty_cycle[output] * output_clock_period,
+	         output_clock_period);
     }
 }
 
-float Pll::FetchParam(RTLIL::Cell* cell, std::string&& param_name, float default_value) {
+float Pll::FetchParam(RTLIL::Cell* cell, std::string&& param_name,
+                      float default_value) {
     RTLIL::IdString param(RTLIL::escape_id(param_name));
     if (cell->hasParam(param)) {
 	auto param_obj = cell->parameters.at(param);
diff --git a/sdc-plugin/buffers.h b/sdc-plugin/buffers.h
index b0ab049..ba3faa4 100644
--- a/sdc-plugin/buffers.h
+++ b/sdc-plugin/buffers.h
@@ -45,9 +45,10 @@
     std::string type;
 };
 
-struct Pll: public ClockDivider {
-    Pll():ClockDivider({"PLLE2_ADV"}){}
-    Pll(RTLIL::Cell* cell, float input_clock_period, float input_clock_rising_edge);
+struct Pll : public ClockDivider {
+    Pll() : ClockDivider({"PLLE2_ADV"}) {}
+    Pll(RTLIL::Cell* cell, float input_clock_period,
+        float input_clock_rising_edge);
 
     // Helper function to fetch a cell parameter or return a default value
     static float FetchParam(RTLIL::Cell* cell, std::string&& param_name,
diff --git a/sdc-plugin/clocks.cc b/sdc-plugin/clocks.cc
index 2c12ccd..9f259d5 100644
--- a/sdc-plugin/clocks.cc
+++ b/sdc-plugin/clocks.cc
@@ -19,32 +19,65 @@
 #include <cassert>
 #include <cmath>
 #include <regex>
-#include "kernel/log.h"
 #include "kernel/register.h"
 #include "propagation.h"
 
+void Clock::Add(const std::string& name, RTLIL::Wire* wire, float period,
+                float rising_edge, float falling_edge) {
+    wire->set_string_attribute(RTLIL::escape_id("CLOCK_SIGNAL"), "yes");
+    wire->set_string_attribute(RTLIL::escape_id("CLASS"), "clock");
+    wire->set_string_attribute(RTLIL::escape_id("NAME"), name);
+    wire->set_string_attribute(RTLIL::escape_id("SOURCE_PINS"),
+                               Clock::ClockWireName(wire));
+    wire->set_string_attribute(RTLIL::escape_id("PERIOD"),
+                               std::to_string(period));
+    std::string waveform(std::to_string(rising_edge) + " " +
+                         std::to_string(falling_edge));
+    wire->set_string_attribute(RTLIL::escape_id("WAVEFORM"), waveform);
+}
+
+void Clock::Add(const std::string& name, std::vector<RTLIL::Wire*> wires,
+                float period, float rising_edge, float falling_edge) {
+    std::for_each(wires.begin(), wires.end(), [&](RTLIL::Wire* wire) {
+	Add(name, wire, period, rising_edge, falling_edge);
+    });
+}
+
+void Clock::Add(RTLIL::Wire* wire, float period, float rising_edge,
+                float falling_edge) {
+    Add(Clock::ClockWireName(wire), wire, period, rising_edge, falling_edge);
+}
+
 float Clock::Period(RTLIL::Wire* clock_wire) {
     if (!clock_wire->has_attribute(RTLIL::escape_id("PERIOD"))) {
-	log_warning("Period has not been specified\n Default value 0 will be used\n");
+	log_warning(
+	    "Period has not been specified\n Default value 0 will be used\n");
 	return 0;
     }
-    return std::stof(clock_wire->get_string_attribute(RTLIL::escape_id("PERIOD")));
+    return std::stof(
+        clock_wire->get_string_attribute(RTLIL::escape_id("PERIOD")));
 }
 
 std::pair<float, float> Clock::Waveform(RTLIL::Wire* clock_wire) {
     if (!clock_wire->has_attribute(RTLIL::escape_id("WAVEFORM"))) {
 	float period(Period(clock_wire));
 	if (!period) {
-	    log_cmd_error("Neither PERIOD nor WAVEFORM has been specified for wire %s\n", ClockWireName(clock_wire).c_str());
-	    return std::make_pair(0,0);
+	    log_cmd_error(
+	        "Neither PERIOD nor WAVEFORM has been specified for wire %s\n",
+	        ClockWireName(clock_wire).c_str());
+	    return std::make_pair(0, 0);
 	}
 	float falling_edge = period / 2;
-	log_warning("Waveform has not been specified\n Default value {0 %f} will be used\n", falling_edge);
+	log_warning(
+	    "Waveform has not been specified\n Default value {0 %f} will be "
+	    "used\n",
+	    falling_edge);
 	return std::make_pair(0, falling_edge);
     }
     float rising_edge(0);
     float falling_edge(0);
-    std::string waveform(clock_wire->get_string_attribute(RTLIL::escape_id("WAVEFORM")));
+    std::string waveform(
+        clock_wire->get_string_attribute(RTLIL::escape_id("WAVEFORM")));
     std::sscanf(waveform.c_str(), "%f %f", &rising_edge, &falling_edge);
     return std::make_pair(rising_edge, falling_edge);
 }
@@ -65,115 +98,18 @@
     return std::regex_replace(wire_name, std::regex{"\\$"}, "\\$");
 }
 
-void Clocks::AddClock(const std::string& name, std::vector<RTLIL::Wire*> wires,
-                      float period, float rising_edge, float falling_edge) {
-    std::for_each(wires.begin(), wires.end(), [&](RTLIL::Wire* wire) {
-	AddClock(name, wire, period, rising_edge, falling_edge);
-    });
-}
-
-void Clocks::AddClock(const std::string& name, RTLIL::Wire* wire, float period,
-                      float rising_edge, float falling_edge) {
-    wire->set_string_attribute(RTLIL::escape_id("CLOCK_SIGNAL"), "yes");
-    wire->set_string_attribute(RTLIL::escape_id("CLASS"), "clock");
-    wire->set_string_attribute(RTLIL::escape_id("NAME"), name);
-    wire->set_string_attribute(RTLIL::escape_id("SOURCE_PINS"), Clock::ClockWireName(wire));
-    wire->set_string_attribute(RTLIL::escape_id("PERIOD"), std::to_string(period));
-    std::string waveform(std::to_string(rising_edge) + " " + std::to_string(falling_edge));
-    wire->set_string_attribute(RTLIL::escape_id("WAVEFORM"), waveform);
-}
-
-void Clocks::AddClock(RTLIL::Wire* wire, float period,
-                      float rising_edge, float falling_edge) {
-    AddClock(Clock::ClockWireName(wire), wire, period, rising_edge, falling_edge);
-}
-
 const std::vector<RTLIL::Wire*> Clocks::GetClocks(RTLIL::Design* design) {
     std::vector<RTLIL::Wire*> clock_wires;
     RTLIL::Module* top_module = design->top_module();
     for (auto& wire_obj : top_module->wires_) {
 	auto& wire = wire_obj.second;
 	if (wire->has_attribute(RTLIL::escape_id("CLOCK_SIGNAL"))) {
-		if (wire->get_string_attribute(RTLIL::escape_id("CLOCK_SIGNAL")) == "yes") {
-			clock_wires.push_back(wire);
-		}
+	    if (wire->get_string_attribute(RTLIL::escape_id("CLOCK_SIGNAL")) ==
+	        "yes") {
+		clock_wires.push_back(wire);
+	    }
 	}
     }
     return clock_wires;
 }
 
-void Clocks::Propagate(RTLIL::Design* design, NaturalPropagation* pass) {
-#ifdef SDC_DEBUG
-    log("Start natural clock propagation\n");
-#endif
-    for (auto& clock_wire : Clocks::GetClocks(design)) {
-#ifdef SDC_DEBUG
-	log("Processing clock %s\n", RTLIL::id2cstr(clock_wire->name));
-#endif
-	auto aliases = pass->FindAliasWires(clock_wire);
-	AddClock(Clock::ClockWireName(clock_wire), aliases,
-	         Clock::Period(clock_wire), Clock::RisingEdge(clock_wire),
-	         Clock::FallingEdge(clock_wire));
-    }
-#ifdef SDC_DEBUG
-    log("Finish natural clock propagation\n\n");
-#endif
-}
-
-void Clocks::Propagate(RTLIL::Design* design, BufferPropagation* pass) {
-#ifdef SDC_DEBUG
-    log("Start buffer clock propagation\n");
-    log("IBUF pass\n");
-#endif
-    PropagateThroughBuffers(pass, design, IBuf());
-#ifdef SDC_DEBUG
-    log("BUFG pass\n");
-#endif
-    PropagateThroughBuffers(pass, design, Bufg());
-#ifdef SDC_DEBUG
-    log("Finish buffer clock propagation\n\n");
-#endif
-}
-
-void Clocks::Propagate(RTLIL::Design* design, ClockDividerPropagation* pass) {
-#ifdef SDC_DEBUG
-    log("Start clock divider clock propagation\n");
-#endif
-    PropagateThroughClockDividers(pass, design, Pll());
-    PropagateThroughBuffers(pass, design, Bufg());
-#ifdef SDC_DEBUG
-    log("Finish clock divider clock propagation\n\n");
-#endif
-}
-
-void Clocks::PropagateThroughBuffers(Propagation* pass, RTLIL::Design* design,
-                                    Buffer buffer) {
-    for (auto& clock_wire : Clocks::GetClocks(design)) {
-#ifdef SDC_DEBUG
-	log("Clock wire %s\n", Clock::ClockWireName(clock_wire).c_str());
-#endif
-	auto buf_wires = pass->FindSinkWiresForCellType(clock_wire, buffer.type,
-	                                                buffer.output);
-	int path_delay(0);
-	for (auto wire : buf_wires) {
-#ifdef SDC_DEBUG
-	    log("%s wire: %s\n", buffer.type.c_str(),
-	        RTLIL::id2cstr(wire->name));
-#endif
-	    path_delay += buffer.delay;
-	    AddClock(wire, Clock::Period(clock_wire),
-	             Clock::RisingEdge(clock_wire) + path_delay,
-	             Clock::FallingEdge(clock_wire) + path_delay);
-	}
-    }
-}
-
-void Clocks::PropagateThroughClockDividers(ClockDividerPropagation* pass, RTLIL::Design* design,
-                                    ClockDivider divider) {
-    for (auto& clock_wire : Clocks::GetClocks(design)) {
-#ifdef SDC_DEBUG
-	log("Processing clock %s\n", Clock::ClockWireName(clock_wire).c_str());
-#endif
-	pass->PropagateClocksForCellType(clock_wire, divider.type);
-    }
-}
diff --git a/sdc-plugin/clocks.h b/sdc-plugin/clocks.h
index 4b8a9e4..6fab3ea 100644
--- a/sdc-plugin/clocks.h
+++ b/sdc-plugin/clocks.h
@@ -31,6 +31,12 @@
 
 class Clock {
    public:
+    static void Add(const std::string& name, RTLIL::Wire* wire, float period,
+                  float rising_edge, float falling_edge);
+    static void Add(const std::string& name, std::vector<RTLIL::Wire*> wires,
+                  float period, float rising_edge, float falling_edge);
+    static void Add(RTLIL::Wire* wire, float period,
+                  float rising_edge, float falling_edge);
     static float Period(RTLIL::Wire* clock_wire);
     static float RisingEdge(RTLIL::Wire* clock_wire);
     static float FallingEdge(RTLIL::Wire* clock_wire);
@@ -42,22 +48,7 @@
 
 class Clocks {
    public:
-    static void AddClock(const std::string& name, std::vector<RTLIL::Wire*> wires,
-                  float period, float rising_edge, float falling_edge);
-    static void AddClock(const std::string& name, RTLIL::Wire* wire, float period,
-                  float rising_edge, float falling_edge);
-    static void AddClock(RTLIL::Wire* wire, float period,
-                  float rising_edge, float falling_edge);
     static const std::vector<RTLIL::Wire*> GetClocks(RTLIL::Design* design);
-    void Propagate(RTLIL::Design* design, NaturalPropagation* pass);
-    void Propagate(RTLIL::Design* design, BufferPropagation* pass);
-    void Propagate(RTLIL::Design* design, ClockDividerPropagation* pass);
-
-   private:
-    void PropagateThroughBuffers(Propagation* pass, RTLIL::Design* design,
-                                Buffer buffer);
-    void PropagateThroughClockDividers(ClockDividerPropagation* pass, RTLIL::Design* design,
-                                ClockDivider divider);
 };
 
 #endif  // _CLOCKS_H_
diff --git a/sdc-plugin/propagation.cc b/sdc-plugin/propagation.cc
index 71ce467..dc24d00 100644
--- a/sdc-plugin/propagation.cc
+++ b/sdc-plugin/propagation.cc
@@ -20,47 +20,44 @@
 
 USING_YOSYS_NAMESPACE
 
-std::vector<RTLIL::Wire*> NaturalPropagation::FindAliasWires(
-    RTLIL::Wire* wire) {
-    RTLIL::Module* top_module = design_->top_module();
-    assert(top_module);
-    std::vector<RTLIL::Wire*> alias_wires;
-    pass_->extra_args(
-        std::vector<std::string>{
-            top_module->name.str() + "/w:" + wire->name.str(), "%a"},
-        0, design_);
-    for (auto module : design_->selected_modules()) {
-	for (auto wire : module->selected_wires()) {
-	    alias_wires.push_back(wire);
+void Propagation::PropagateThroughBuffers(Buffer buffer) {
+    for (auto& clock_wire : Clocks::GetClocks(design_)) {
+#ifdef SDC_DEBUG
+	log("Clock wire %s\n", Clock::ClockWireName(clock_wire).c_str());
+#endif
+	auto buf_wires =
+	    FindSinkWiresForCellType(clock_wire, buffer.type, buffer.output);
+	int path_delay(0);
+	for (auto wire : buf_wires) {
+#ifdef SDC_DEBUG
+	    log("%s wire: %s\n", buffer.type.c_str(),
+	        RTLIL::id2cstr(wire->name));
+#endif
+	    path_delay += buffer.delay;
+	    Clock::Add(wire, Clock::Period(clock_wire),
+	               Clock::RisingEdge(clock_wire) + path_delay,
+	               Clock::FallingEdge(clock_wire) + path_delay);
 	}
     }
-    return alias_wires;
 }
 
-void ClockDividerPropagation::PropagateClocksForCellType(
-    RTLIL::Wire* driver_wire, const std::string& cell_type) {
-    if (cell_type == "PLLE2_ADV") {
-	RTLIL::Cell* cell = NULL;
-	for (auto input : Pll::inputs) {
-	    cell = FindSinkCellOnPort(driver_wire, input);
-	    if (cell and RTLIL::unescape_id(cell->type) == cell_type) {
-		break;
-	    }
-	}
-	if (!cell) {
-	    return;
-	}
-	Pll pll(cell, Clock::Period(driver_wire), Clock::RisingEdge(driver_wire));
-	for (auto output : Pll::outputs) {
-	    RTLIL::Wire* wire = FindSinkWireOnPort(cell, output);
-	    if (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));
-		Clocks::AddClock(wire, clkout_period, clkout_rising_edge, clkout_falling_edge);
-	    }
-	}
+std::vector<RTLIL::Wire*> Propagation::FindSinkWiresForCellType(
+    RTLIL::Wire* driver_wire, const std::string& cell_type,
+    const std::string& cell_port) {
+    std::vector<RTLIL::Wire*> wires;
+    if (!driver_wire) {
+	return wires;
     }
+    auto cell = FindSinkCellOfType(driver_wire, cell_type);
+    RTLIL::Wire* wire = FindSinkWireOnPort(cell, cell_port);
+    if (wire) {
+	wires.push_back(wire);
+	auto further_wires =
+	    FindSinkWiresForCellType(wire, cell_type, cell_port);
+	std::copy(further_wires.begin(), further_wires.end(),
+	          std::back_inserter(wires));
+    }
+    return wires;
 }
 
 RTLIL::Cell* Propagation::FindSinkCellOfType(RTLIL::Wire* wire,
@@ -89,25 +86,6 @@
     return sink_cell;
 }
 
-std::vector<RTLIL::Wire*> Propagation::FindSinkWiresForCellType(
-    RTLIL::Wire* driver_wire, const std::string& cell_type,
-    const std::string& cell_port) {
-    std::vector<RTLIL::Wire*> wires;
-    if (!driver_wire) {
-	return wires;
-    }
-    auto cell = FindSinkCellOfType(driver_wire, cell_type);
-    RTLIL::Wire* wire = FindSinkWireOnPort(cell, cell_port);
-    if (wire) {
-	wires.push_back(wire);
-	auto further_wires =
-	    FindSinkWiresForCellType(wire, cell_type, cell_port);
-	std::copy(further_wires.begin(), further_wires.end(),
-	          std::back_inserter(wires));
-    }
-    return wires;
-}
-
 RTLIL::Cell* Propagation::FindSinkCellOnPort(RTLIL::Wire* wire,
                                              const std::string& port) {
     RTLIL::Cell* sink_cell = NULL;
@@ -161,3 +139,102 @@
     }
     return sink_wire;
 }
+void NaturalPropagation::Run() {
+#ifdef SDC_DEBUG
+    log("Start natural clock propagation\n");
+#endif
+    for (auto& clock_wire : Clocks::GetClocks(design_)) {
+#ifdef SDC_DEBUG
+	log("Processing clock %s\n", RTLIL::id2cstr(clock_wire->name));
+#endif
+	auto aliases = FindAliasWires(clock_wire);
+	Clock::Add(Clock::ClockWireName(clock_wire), aliases,
+	           Clock::Period(clock_wire), Clock::RisingEdge(clock_wire),
+	           Clock::FallingEdge(clock_wire));
+    }
+#ifdef SDC_DEBUG
+    log("Finish natural clock propagation\n\n");
+#endif
+}
+
+std::vector<RTLIL::Wire*> NaturalPropagation::FindAliasWires(
+    RTLIL::Wire* wire) {
+    RTLIL::Module* top_module = design_->top_module();
+    assert(top_module);
+    std::vector<RTLIL::Wire*> alias_wires;
+    pass_->extra_args(
+        std::vector<std::string>{
+            top_module->name.str() + "/w:" + wire->name.str(), "%a"},
+        0, design_);
+    for (auto module : design_->selected_modules()) {
+	for (auto wire : module->selected_wires()) {
+	    alias_wires.push_back(wire);
+	}
+    }
+    return alias_wires;
+}
+
+void BufferPropagation::Run() {
+#ifdef SDC_DEBUG
+    log("Start buffer clock propagation\n");
+    log("IBUF pass\n");
+#endif
+    PropagateThroughBuffers(IBuf());
+#ifdef SDC_DEBUG
+    log("BUFG pass\n");
+#endif
+    PropagateThroughBuffers(Bufg());
+#ifdef SDC_DEBUG
+    log("Finish buffer clock propagation\n\n");
+#endif
+}
+
+void ClockDividerPropagation::Run() {
+#ifdef SDC_DEBUG
+    log("Start clock divider clock propagation\n");
+#endif
+    PropagateThroughClockDividers(Pll());
+    PropagateThroughBuffers(Bufg());
+#ifdef SDC_DEBUG
+    log("Finish clock divider clock propagation\n\n");
+#endif
+}
+
+void ClockDividerPropagation::PropagateThroughClockDividers(
+    ClockDivider divider) {
+    for (auto& clock_wire : Clocks::GetClocks(design_)) {
+#ifdef SDC_DEBUG
+	log("Processing clock %s\n", Clock::ClockWireName(clock_wire).c_str());
+#endif
+	PropagateClocksForCellType(clock_wire, divider.type);
+    }
+}
+
+void ClockDividerPropagation::PropagateClocksForCellType(
+    RTLIL::Wire* driver_wire, const std::string& cell_type) {
+    if (cell_type == "PLLE2_ADV") {
+	RTLIL::Cell* cell = NULL;
+	for (auto input : Pll::inputs) {
+	    cell = FindSinkCellOnPort(driver_wire, input);
+	    if (cell and RTLIL::unescape_id(cell->type) == cell_type) {
+		break;
+	    }
+	}
+	if (!cell) {
+	    return;
+	}
+	Pll pll(cell, Clock::Period(driver_wire),
+	        Clock::RisingEdge(driver_wire));
+	for (auto output : Pll::outputs) {
+	    RTLIL::Wire* wire = FindSinkWireOnPort(cell, output);
+	    if (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));
+		Clock::Add(wire, clkout_period, clkout_rising_edge,
+		           clkout_falling_edge);
+	    }
+	}
+    }
+}
+
diff --git a/sdc-plugin/propagation.h b/sdc-plugin/propagation.h
index f9f06ac..788b138 100644
--- a/sdc-plugin/propagation.h
+++ b/sdc-plugin/propagation.h
@@ -26,17 +26,18 @@
    public:
     Propagation(RTLIL::Design* design, Pass* pass)
         : design_(design), pass_(pass) {}
-    virtual ~Propagation(){}
+    virtual ~Propagation() {}
 
-    virtual void Run(Clocks& clocks) = 0;
-    std::vector<RTLIL::Wire*> FindSinkWiresForCellType(
-        RTLIL::Wire* driver_wire, const std::string& cell_type,
-        const std::string& cell_port);
+    virtual void Run() = 0;
 
    protected:
     RTLIL::Design* design_;
     Pass* pass_;
 
+    void PropagateThroughBuffers(Buffer buffer);
+    std::vector<RTLIL::Wire*> FindSinkWiresForCellType(
+        RTLIL::Wire* driver_wire, const std::string& cell_type,
+        const std::string& cell_port);
     RTLIL::Cell* FindSinkCellOfType(RTLIL::Wire* wire, const std::string& type);
     RTLIL::Cell* FindSinkCellOnPort(RTLIL::Wire* wire, const std::string& port);
     RTLIL::Wire* FindSinkWireOnPort(RTLIL::Cell* cell,
@@ -48,7 +49,7 @@
     NaturalPropagation(RTLIL::Design* design, Pass* pass)
         : Propagation(design, pass) {}
 
-    void Run(Clocks& clocks) override { clocks.Propagate(design_, this); }
+    void Run() override;
     std::vector<RTLIL::Wire*> FindAliasWires(RTLIL::Wire* wire);
 };
 
@@ -57,7 +58,7 @@
     BufferPropagation(RTLIL::Design* design, Pass* pass)
         : Propagation(design, pass) {}
 
-    void Run(Clocks& clocks) override { clocks.Propagate(design_, this); }
+    void Run() override;
 };
 
 class ClockDividerPropagation : public Propagation {
@@ -65,8 +66,9 @@
     ClockDividerPropagation(RTLIL::Design* design, Pass* pass)
         : Propagation(design, pass) {}
 
-    void Run(Clocks& clocks) override { clocks.Propagate(design_, this); }
+    void Run() override;
     void PropagateClocksForCellType(RTLIL::Wire* driver_wire,
-                                                 const std::string& cell_type);
+                                    const std::string& cell_type);
+    void PropagateThroughClockDividers(ClockDivider divider);
 };
 #endif  // PROPAGATION_H_
diff --git a/sdc-plugin/sdc.cc b/sdc-plugin/sdc.cc
index 9d55906..b940301 100644
--- a/sdc-plugin/sdc.cc
+++ b/sdc-plugin/sdc.cc
@@ -61,8 +61,8 @@
 };
 
 struct WriteSdcCmd : public Backend {
-    WriteSdcCmd(Clocks& clocks, SdcWriter& sdc_writer)
-        : Backend("sdc", "Write SDC file"), clocks_(clocks), sdc_writer_(sdc_writer) {}
+    WriteSdcCmd(SdcWriter& sdc_writer)
+        : Backend("sdc", "Write SDC file"), sdc_writer_(sdc_writer) {}
 
     void help() override {
 	log("\n");
@@ -82,13 +82,12 @@
 	sdc_writer_.WriteSdc(design, *f);
     }
 
-    Clocks& clocks_;
     SdcWriter& sdc_writer_;
 };
 
 struct CreateClockCmd : public Pass {
-    CreateClockCmd(Clocks& clocks)
-        : Pass("create_clock", "Create clock object"), clocks_(clocks) {}
+    CreateClockCmd()
+        : Pass("create_clock", "Create clock object") {}
 
     void help() override {
 	log("\n");
@@ -170,7 +169,7 @@
 	    rising_edge = 0;
 	    falling_edge = period / 2;
 	}
-	clocks_.AddClock(name, selected_wires, period, rising_edge,
+	Clock::Add(name, selected_wires, period, rising_edge,
 	                 falling_edge);
     }
 
@@ -179,8 +178,6 @@
 	std::transform(selection_begin, args.end(), selection_begin,
 	               [](std::string& w) { return "w:" + w; });
     }
-
-    Clocks& clocks_;
 };
 
 struct GetClocksCmd : public Pass {
@@ -216,9 +213,8 @@
 };
 
 struct PropagateClocksCmd : public Pass {
-    PropagateClocksCmd(Clocks& clocks)
-        : Pass("propagate_clocks", "Propagate clock information"),
-          clocks_(clocks) {}
+    PropagateClocksCmd()
+        : Pass("propagate_clocks", "Propagate clock information") {}
 
     void help() override {
 	log("\n");
@@ -228,8 +224,11 @@
 	log("\n");
     }
 
-    void execute(__attribute__((unused)) std::vector<std::string> args,
+    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");
+	}
 	if (!design->top_module()) {
 	    log_cmd_error("No top module selected\n");
 	}
@@ -243,19 +242,15 @@
 	log("Perform clock propagation\n");
 
 	for (auto& pass : passes) {
-	    pass->Run(clocks_);
+	    pass->Run();
 	}
     }
-
-    Clocks& clocks_;
 };
 
 class SdcPlugin {
    public:
     SdcPlugin()
-        : write_sdc_cmd_(clocks_, sdc_writer_),
-          create_clock_cmd_(clocks_),
-          propagate_clocks_cmd_(clocks_),
+        : write_sdc_cmd_(sdc_writer_),
           set_false_path_cmd_(sdc_writer_),
           set_max_delay_cmd_(sdc_writer_),
           set_clock_groups_cmd_(sdc_writer_) {
@@ -272,7 +267,6 @@
     SetClockGroups set_clock_groups_cmd_;
 
    private:
-    Clocks clocks_;
     SdcWriter sdc_writer_;
 } SdcPlugin;
 
diff --git a/sdc-plugin/tests/counter/counter.tcl b/sdc-plugin/tests/counter/counter.tcl
index 4fcf9be..b045b3c 100644
--- a/sdc-plugin/tests/counter/counter.tcl
+++ b/sdc-plugin/tests/counter/counter.tcl
@@ -24,3 +24,4 @@
 
 # Write out the SDC file after the clock propagation step
 write_sdc $::env(DESIGN_TOP).sdc
+write_json $::env(DESIGN_TOP).json