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_