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")