SDC: Add duty cycle and input clock delay to output clock Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/sdc-plugin/buffers.h b/sdc-plugin/buffers.h index 024416b..fcce64f 100644 --- a/sdc-plugin/buffers.h +++ b/sdc-plugin/buffers.h
@@ -61,12 +61,32 @@ divclk_divisor = cell->getParam(ID(DIVCLK_DIVIDE)).as_int(); } for (auto clk_output : outputs) { + // CLKOUT[0-5]_DIVIDE RTLIL::IdString param(RTLIL::escape_id(clk_output + "_DIVIDE")); if (cell->hasParam(param)) { clkout_divisors[clk_output] = cell->getParam(param).as_int(); } else { clkout_divisors[clk_output] = 1; } + clkout_period[clk_output] = CalculatePeriod(clk_output); + + // CLKOUT[0-5]_PHASE + param = RTLIL::escape_id(clk_output + "_PHASE"); + if (cell->hasParam(param)) { + clkout_phase[clk_output] = std::stof(cell->getParam(param).decode_string()); + } else { + clkout_phase[clk_output] = 0.0; + } + // Take the delay off the PLL into account + clkout_shift[clk_output] = CalculateShift(clk_output) + delay; + + // CLKOUT[0-5]_DUTY_CYCLE + param = RTLIL::escape_id(clk_output + "_DUTY_CYCLE"); + if (cell->hasParam(param)) { + clkout_duty_cycle[clk_output] = std::stof(cell->getParam(param).decode_string()); + } else { + clkout_duty_cycle[clk_output] = 0.5; + } } }; @@ -78,6 +98,10 @@ divclk_divisor; } + float CalculateShift(const std::string& output) { + return clkout_period.at(output) * clkout_phase.at(output) / 360.0; + } + static const float delay; static const std::string name; static const std::vector<std::string> inputs; @@ -85,6 +109,10 @@ RTLIL::Cell* cell; float clkin1_period = 0; float clkin2_period = 0; + std::unordered_map<std::string, float> clkout_period; + std::unordered_map<std::string, float> clkout_duty_cycle; + std::unordered_map<std::string, float> clkout_phase; + std::unordered_map<std::string, float> clkout_shift; std::unordered_map<std::string, int> clkout_divisors; int divclk_divisor = 1; int clk_mult = 5;
diff --git a/sdc-plugin/clocks.cc b/sdc-plugin/clocks.cc index ce1b704..3854108 100644 --- a/sdc-plugin/clocks.cc +++ b/sdc-plugin/clocks.cc
@@ -128,6 +128,7 @@ #ifdef SDC_DEBUG log("PLL clock: %s\n", pll_clock.Name().c_str()); #endif + pll_clock.ApplyShift(clock.RisingEdge()); AddClock(pll_clock); PropagateThroughBuffer(pass, pll_clock, Bufg()); } @@ -224,6 +225,14 @@ falling_edge_ = falling_edge; } +void Clock::ApplyShift(float rising_edge) { + rising_edge_ += rising_edge; + falling_edge_ += rising_edge; + if (falling_edge_ > period_) { + log_error("Phase shift exceeds 360 degrees\n"); + } +} + std::string Clock::ClockWireName(RTLIL::Wire* wire) { if (!wire) { return std::string();
diff --git a/sdc-plugin/clocks.h b/sdc-plugin/clocks.h index faa8aec..28cd7f7 100644 --- a/sdc-plugin/clocks.h +++ b/sdc-plugin/clocks.h
@@ -43,6 +43,7 @@ float FallingEdge() { return falling_edge_; } void UpdateClock(RTLIL::Wire* wire, float period, float rising_edge, float falling_edge); + void ApplyShift(float shift); static std::string ClockWireName(RTLIL::Wire* wire); private:
diff --git a/sdc-plugin/propagation.cc b/sdc-plugin/propagation.cc index 35e86f3..39ea476 100644 --- a/sdc-plugin/propagation.cc +++ b/sdc-plugin/propagation.cc
@@ -55,9 +55,11 @@ for (auto output : Pll::outputs) { RTLIL::Wire* wire = FindSinkWireOnPort(cell, output); if (wire) { - float period(pll.CalculatePeriod(output)); - Clock clock(RTLIL::unescape_id(wire->name), wire, period, 0, - period / 2); + float clkout_period(pll.clkout_period.at(output)); + float clkout_shift(pll.clkout_shift.at(output)); + float clkout_duty_cycle(pll.clkout_duty_cycle.at(output)); + Clock clock(RTLIL::unescape_id(wire->name), wire, clkout_period, clkout_shift, + clkout_shift + clkout_duty_cycle * clkout_period); clocks.push_back(clock); auto further_clocks = FindSinkClocksForCellType(wire, cell_type);
diff --git a/sdc-plugin/tests/pll/pll.golden.sdc b/sdc-plugin/tests/pll/pll.golden.sdc index c6ba07a..4080fa4 100644 --- a/sdc-plugin/tests/pll/pll.golden.sdc +++ b/sdc-plugin/tests/pll/pll.golden.sdc
@@ -1,6 +1,6 @@ create_clock -period 10 -waveform {0 5} \$auto\$clkbufmap.cc:247:execute\$1827 create_clock -period 10 -waveform {1 6} \$techmap1716\FDCE_0.C -create_clock -period 10 -waveform {0 5} \$auto\$clkbufmap.cc:247:execute\$1829 -create_clock -period 10 -waveform {1 6} main_clkout0 -create_clock -period 2.5 -waveform {0 1.25} \$auto\$clkbufmap.cc:247:execute\$1831 -create_clock -period 2.5 -waveform {1 2.25} main_clkout1 +create_clock -period 10 -waveform {3.5 8.5} \$auto\$clkbufmap.cc:247:execute\$1829 +create_clock -period 10 -waveform {4.5 9.5} main_clkout0 +create_clock -period 2.5 -waveform {1 2.25} \$auto\$clkbufmap.cc:247:execute\$1831 +create_clock -period 2.5 -waveform {2 3.25} main_clkout1
diff --git a/sdc-plugin/tests/pll/pll.v b/sdc-plugin/tests/pll/pll.v index 1bb3a97..17a0064 100644 --- a/sdc-plugin/tests/pll/pll.v +++ b/sdc-plugin/tests/pll/pll.v
@@ -30,9 +30,9 @@ .CLKFBOUT_MULT(4'd12), .CLKIN1_PERIOD(10.0), .CLKOUT0_DIVIDE(4'd12), - .CLKOUT0_PHASE(1'd0), + .CLKOUT0_PHASE(90.0), .CLKOUT1_DIVIDE(2'd3), - .CLKOUT1_PHASE(1'd0), + .CLKOUT1_PHASE(0.0), .DIVCLK_DIVIDE(1'd1), .REF_JITTER1(0.01), .STARTUP_WAIT("FALSE")