SDC: Implement approximate equality check of input clock period Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/sdc-plugin/buffers.cc b/sdc-plugin/buffers.cc index ab99888..709c7f9 100644 --- a/sdc-plugin/buffers.cc +++ b/sdc-plugin/buffers.cc
@@ -27,17 +27,22 @@ Pll::Pll(RTLIL::Cell* cell, float input_clock_period, float input_clock_shift) { assert(RTLIL::unescape_id(cell->type) == "PLLE2_ADV"); - FetchParams(cell); - if (clkin1_period != input_clock_period) { - log_cmd_error( - "CLKIN1_PERIOD doesn't match the virtual clock constraint " - "propagated to the CLKIN1 input of the clock divider cell: " - "%s.\nInput clock period: %f, CLKIN1_PERIOD: %f\n", - RTLIL::id2cstr(cell->name), input_clock_period, clkin1_period); - } + CheckInputClockPeriod(cell, input_clock_period); CalculateOutputClockPeriods(); - CalculateOutputClockWaveforms(input_clock_period, input_clock_shift); + CalculateOutputClockWaveforms(input_clock_shift); +} + +void Pll::CheckInputClockPeriod(RTLIL::Cell* cell, float input_clock_period) { + float abs_diff = fabs(ClkinPeriod() - input_clock_period); + bool approx_equal = abs_diff < max(ClkinPeriod(), input_clock_period) * kApproxEqualFactor; + if (!approx_equal) { + log_cmd_error( + "CLKIN[1/2]_PERIOD isn't approximately equal (+/-%.2f%%) to the virtual clock constraint " + "propagated to the CLKIN[1/2] input of the clock divider cell: " + "%s.\nInput clock period: %f, CLKIN[1/2]_PERIOD: %f\n", + kApproxEqualFactor * 100, RTLIL::id2cstr(cell->name), input_clock_period, ClkinPeriod()); + } } void Pll::FetchParams(RTLIL::Cell* cell) { @@ -60,15 +65,15 @@ for (auto output : outputs) { // CLKOUT[0-5]_PERIOD = CLKIN1_PERIOD * CLKOUT[0-5]_DIVIDE * DIVCLK_DIVIDE / // CLKFBOUT_MULT - clkout_period[output] = clkin1_period * clkout_divisor.at(output) / clk_mult * + clkout_period[output] = ClkinPeriod() * clkout_divisor.at(output) / clk_mult * divclk_divisor; } } -void Pll::CalculateOutputClockWaveforms(float input_clock_period, float input_clock_shift) { +void Pll::CalculateOutputClockWaveforms(float input_clock_shift) { for (auto output : outputs) { float output_clock_period = clkout_period.at(output); - clkout_rising_edge[output] = fmod(input_clock_shift - (clk_fbout_phase / 360.0) * input_clock_period + output_clock_period * (clkout_phase[output] / 360.0), output_clock_period); + clkout_rising_edge[output] = fmod(input_clock_shift - (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); } }
diff --git a/sdc-plugin/buffers.h b/sdc-plugin/buffers.h index d3f7c30..2797f52 100644 --- a/sdc-plugin/buffers.h +++ b/sdc-plugin/buffers.h
@@ -44,6 +44,10 @@ struct Pll { Pll(RTLIL::Cell* cell, float input_clock_period, float input_clock_shift); + // Approximate equality check of the input clock period and specified in CLKIN[1/2]_PERIOD parameter + // kApproxEqualFactor specifies the percentage of the maximum accepted difference + void CheckInputClockPeriod(RTLIL::Cell* cell, float input_clock_period); + // Fetch cell's parameters needed for further calculations void FetchParams(RTLIL::Cell* cell); @@ -51,11 +55,15 @@ void CalculateOutputClockPeriods(); // Calculate the rising and falling edges of the output clocks - void CalculateOutputClockWaveforms(float input_clock_period, float input_clock_shift); + void CalculateOutputClockWaveforms(float input_clock_shift); // Helper function to fetch a cell parameter or return a default value static float FetchParam(RTLIL::Cell* cell, std::string&& param_name, float default_value); + // Get the period of the input clock + // TODO Add support for CLKINSEL + float ClkinPeriod() { return clkin1_period; } + static const float delay; static const std::string name; static const std::vector<std::string> inputs; @@ -71,6 +79,8 @@ float divclk_divisor; float clk_mult; float clk_fbout_phase; + // Approximate equality factor of 1% + const float kApproxEqualFactor = 0.01; }; #endif // _BUFFERS_H_