diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3fe44d6e..981c73d2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -70,6 +70,7 @@ set(STA_SOURCE
dcalc/UnitDelayCalc.cc
graph/DelayFloat.cc
+ graph/DelayNormal1.cc
graph/DelayNormal2.cc
graph/Graph.cc
graph/GraphCmp.cc
@@ -227,6 +228,7 @@ set(STA_HEADERS
graph/Delay.hh
graph/DelayFloat.hh
+ graph/DelayNormal1.hh
graph/DelayNormal2.hh
graph/Graph.hh
graph/GraphClass.hh
diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt
index a72ceb43..12083100 100644
Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ
diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf
index 8b617e51..8e7a3b33 100644
Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ
diff --git a/graph/Delay.hh b/graph/Delay.hh
index dd3bd551..4a3014a6 100644
--- a/graph/Delay.hh
+++ b/graph/Delay.hh
@@ -19,7 +19,10 @@
#ifndef STA_DELAY_H
#define STA_DELAY_H
-#if SSTA
+#if (SSTA == 1)
+ // Delays are Normal PDFs with early/late sigma.
+ #include "DelayNormal1.hh"
+#elif (SSTA == 2)
// Delays are Normal PDFs with early/late sigma.
#include "DelayNormal2.hh"
#else
diff --git a/graph/DelayNormal1.cc b/graph/DelayNormal1.cc
new file mode 100644
index 00000000..1c52a889
--- /dev/null
+++ b/graph/DelayNormal1.cc
@@ -0,0 +1,419 @@
+// OpenSTA, Static Timing Analyzer
+// Copyright (c) 2019, Parallax Software, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "StaConfig.hh"
+#include // sqrt
+#include "Machine.hh"
+#include "Error.hh"
+#include "StringUtil.hh"
+#include "Fuzzy.hh"
+#include "Units.hh"
+#include "StaState.hh"
+#include "Delay.hh"
+
+// SSTA compilation.
+#if (SSTA == 1)
+
+namespace sta {
+
+inline float
+square(float x)
+{
+ return x * x;
+}
+
+static Delay delay_init_values[MinMax::index_count];
+
+void
+initDelayConstants()
+{
+ delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
+ delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
+}
+
+const Delay &
+delayInitValue(const MinMax *min_max)
+{
+ return delay_init_values[min_max->index()];
+}
+
+Delay::Delay() :
+ mean_(0.0),
+ sigma2_{0.0}
+{
+}
+
+Delay::Delay(float mean) :
+ mean_(mean),
+ sigma2_{0.0}
+{
+}
+
+Delay::Delay(float mean,
+ float sigma2) :
+ mean_(mean),
+ sigma2_{sigma2}
+{
+}
+
+float
+Delay::sigma() const
+{
+ if (sigma2_ < 0.0)
+ // Sigma is negative for crpr to offset sigmas in the common
+ // clock path.
+ return -sqrt(-sigma2_);
+ else
+ return sqrt(sigma2_);
+}
+
+float
+Delay::sigma2() const
+{
+ return sigma2_;
+}
+
+void
+Delay::operator=(const Delay &delay)
+{
+ mean_ = delay.mean_;
+ sigma2_ = delay.sigma2_;
+}
+
+void
+Delay::operator=(float delay)
+{
+ mean_ = delay;
+ sigma2_ = 0.0;
+}
+
+void
+Delay::operator+=(const Delay &delay)
+{
+ mean_ += delay.mean_;
+ sigma2_ += delay.sigma2_;
+}
+
+void
+Delay::operator+=(float delay)
+{
+ mean_ += delay;
+}
+
+Delay
+Delay::operator+(const Delay &delay) const
+{
+ return Delay(mean_ + delay.mean_,
+ sigma2_ + delay.sigma2_);
+}
+
+Delay
+Delay::operator+(float delay) const
+{
+ return Delay(mean_ + delay, sigma2_);
+}
+
+Delay
+Delay::operator-(const Delay &delay) const
+{
+ return Delay(mean_ - delay.mean_,
+ sigma2_ + delay.sigma2_);
+}
+
+Delay
+Delay::operator-(float delay) const
+{
+ return Delay(mean_ - delay, sigma2_);
+}
+
+Delay
+Delay::operator-() const
+{
+ return Delay(-mean_, sigma2_);
+}
+
+void
+Delay::operator-=(float delay)
+{
+ mean_ -= delay;
+}
+
+void
+Delay::operator-=(const Delay &delay)
+{
+ mean_ -= delay.mean_;
+ sigma2_ -= delay.sigma2_;
+}
+
+bool
+Delay::operator==(const Delay &delay) const
+{
+ return mean_ == delay.mean_
+ && sigma2_ == delay.sigma2_;
+}
+
+bool
+Delay::operator>(const Delay &delay) const
+{
+ return mean_ > delay.mean_;
+}
+
+bool
+Delay::operator>=(const Delay &delay) const
+{
+ return mean_ >= delay.mean_;
+}
+
+bool
+Delay::operator<(const Delay &delay) const
+{
+ return mean_ < delay.mean_;
+}
+
+bool
+Delay::operator<=(const Delay &delay) const
+{
+ return mean_ <= delay.mean_;
+}
+
+////////////////////////////////////////////////////////////////
+
+Delay
+makeDelay(float delay,
+ float sigma,
+ float)
+{
+ return Delay(delay, square(sigma));
+}
+
+Delay
+makeDelay2(float delay,
+ float sigma2,
+ float )
+{
+ return Delay(delay, sigma2);
+}
+
+bool
+delayIsInitValue(const Delay &delay,
+ const MinMax *min_max)
+{
+ return fuzzyEqual(delay.mean(), min_max->initValue())
+ && delay.sigma2() == 0.0;
+}
+
+bool
+fuzzyZero(const Delay &delay)
+{
+ return fuzzyZero(delay.mean())
+ && fuzzyZero(delay.sigma2());
+}
+
+bool
+fuzzyEqual(const Delay &delay1,
+ const Delay &delay2)
+{
+ return fuzzyEqual(delay1.mean(), delay2.mean())
+ && fuzzyEqual(delay1.sigma2(), delay2.sigma2());
+}
+
+bool
+fuzzyLess(const Delay &delay1,
+ const Delay &delay2)
+{
+ return fuzzyLess(delay1.mean(), delay2.mean());
+}
+
+bool
+fuzzyLess(const Delay &delay1,
+ float delay2)
+{
+ return fuzzyLess(delay1.mean(), delay2);
+}
+
+bool
+fuzzyLessEqual(const Delay &delay1,
+ const Delay &delay2)
+{
+ return fuzzyLessEqual(delay1.mean(), delay2.mean());
+}
+
+bool
+fuzzyLessEqual(const Delay &delay1,
+ float delay2)
+{
+ return fuzzyLessEqual(delay1.mean(), delay2);
+}
+
+bool
+fuzzyLessEqual(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max)
+{
+ if (min_max == MinMax::max())
+ return fuzzyLessEqual(delay1.mean(), delay2.mean());
+ else
+ return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
+}
+
+bool
+fuzzyGreater(const Delay &delay1,
+ const Delay &delay2)
+{
+ return fuzzyGreater(delay1.mean(), delay2.mean());
+}
+
+bool
+fuzzyGreater(const Delay &delay1,
+ float delay2)
+{
+ return fuzzyGreater(delay1.mean(), delay2);
+}
+
+bool
+fuzzyGreaterEqual(const Delay &delay1,
+ const Delay &delay2)
+{
+ return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
+}
+
+bool
+fuzzyGreaterEqual(const Delay &delay1,
+ float delay2)
+{
+ return fuzzyGreaterEqual(delay1.mean(), delay2);
+}
+
+bool
+fuzzyGreater(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max)
+{
+ if (min_max == MinMax::max())
+ return fuzzyGreater(delay1.mean(), delay2.mean());
+ else
+ return fuzzyLess(delay1.mean(), delay2.mean());
+}
+
+bool
+fuzzyGreaterEqual(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max)
+{
+ if (min_max == MinMax::max())
+ return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
+ else
+ return fuzzyLessEqual(delay1.mean(), delay2.mean());
+}
+
+bool
+fuzzyLess(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max)
+{
+ if (min_max == MinMax::max())
+ return fuzzyLess(delay1.mean(), delay2.mean());
+ else
+ return fuzzyGreater(delay1.mean(), delay2.mean());
+}
+
+Delay
+operator+(float delay1,
+ const Delay &delay2)
+{
+ return Delay(delay1 + delay2.mean(),
+ delay2.sigma2());
+}
+
+Delay
+operator/(float delay1,
+ const Delay &delay2)
+{
+ return Delay(delay1 / delay2.mean(),
+ delay2.sigma2());
+}
+
+Delay
+operator*(const Delay &delay1,
+ float scale)
+{
+ float scale2 = square(scale);
+ return Delay(delay1.mean() * scale,
+ delay1.sigma2() * scale2);
+}
+
+float
+delayRatio(const Delay &delay1,
+ const Delay &delay2)
+{
+ return delay1.mean() / delay2.mean();
+}
+
+float
+delayAsFloat(const Delay &delay,
+ const EarlyLate *early_late,
+ float sigma_factor)
+{
+ if (early_late == EarlyLate::early())
+ return delay.mean() - delay.sigma() * sigma_factor;
+ else if (early_late == EarlyLate::late())
+ return delay.mean() + delay.sigma() * sigma_factor;
+ else
+ internalError("unknown early/late value.");
+}
+
+float
+delaySigma2(const Delay &delay,
+ const EarlyLate *)
+{
+ return delay.sigma2();
+}
+
+const char *
+delayAsString(const Delay &delay,
+ const StaState *sta)
+{
+ return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
+}
+
+const char *
+delayAsString(const Delay &delay,
+ const StaState *sta,
+ int digits)
+{
+ const Unit *unit = sta->units()->timeUnit();
+ if (sta->pocvEnabled()) {
+ float sigma = delay.sigma();
+ return stringPrintTmp("%s|%s",
+ unit->asString(delay.mean(), digits),
+ unit->asString(sigma, digits));
+ }
+ else
+ return unit->asString(delay.mean(), digits);
+}
+
+const char *
+delayAsString(const Delay &delay,
+ const EarlyLate *early_late,
+ const StaState *sta,
+ int digits)
+{
+ float mean_sigma = delayAsFloat(delay, early_late, sta->sigmaFactor());
+ return sta->units()->timeUnit()->asString(mean_sigma, digits);
+}
+
+} // namespace
+#endif
diff --git a/graph/DelayNormal1.hh b/graph/DelayNormal1.hh
new file mode 100644
index 00000000..a286c934
--- /dev/null
+++ b/graph/DelayNormal1.hh
@@ -0,0 +1,157 @@
+// OpenSTA, Static Timing Analyzer
+// Copyright (c) 2019, Parallax Software, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#ifndef STA_DELAY_NORMAL1_H
+#define STA_DELAY_NORMAL1_H
+
+#include "MinMax.hh"
+
+namespace sta {
+
+class Delay;
+class StaState;
+
+// Normal distribution with std deviation.
+class Delay
+{
+public:
+ Delay();
+ Delay(float mean);
+ Delay(float mean,
+ float sigma2);
+ float mean() const { return mean_; }
+ float sigma() const;
+ // sigma^2
+ float sigma2() const;
+ void operator=(const Delay &delay);
+ void operator=(float delay);
+ void operator+=(const Delay &delay);
+ void operator+=(float delay);
+ Delay operator+(const Delay &delay) const;
+ Delay operator+(float delay) const;
+ Delay operator-(const Delay &delay) const;
+ Delay operator-(float delay) const;
+ Delay operator-() const;
+ void operator-=(float delay);
+ void operator-=(const Delay &delay);
+ bool operator==(const Delay &delay) const;
+ bool operator>(const Delay &delay) const;
+ bool operator>=(const Delay &delay) const;
+ bool operator<(const Delay &delay) const;
+ bool operator<=(const Delay &delay) const;
+
+private:
+ float mean_;
+ // Sigma^2
+ float sigma2_;
+};
+
+const Delay delay_zero(0.0);
+
+void
+initDelayConstants();
+
+Delay
+makeDelay(float delay,
+ float sigma_early,
+ float sigma_late);
+
+Delay
+makeDelay2(float delay,
+ // sigma^2
+ float sigma_early,
+ float sigma_late);
+
+inline float
+delayAsFloat(const Delay &delay) { return delay.mean(); }
+
+// Most non-operator functions on Delay are not defined as member
+// functions so they can be defined on floats, where there is no class
+// to define them.
+
+Delay operator+(float delay1,
+ const Delay &delay2);
+// Used for parallel gate delay calc.
+Delay operator/(float delay1,
+ const Delay &delay2);
+// Used for parallel gate delay calc.
+Delay operator*(const Delay &delay1,
+ float delay2);
+
+// mean late+/early- sigma
+float
+delayAsFloat(const Delay &delay,
+ const EarlyLate *early_late,
+ float sigma_factor);
+float
+delaySigma2(const Delay &delay,
+ const EarlyLate *early_late);
+const char *
+delayAsString(const Delay &delay,
+ const StaState *sta);
+const char *
+delayAsString(const Delay &delay,
+ const StaState *sta,
+ int digits);
+const char *
+delayAsString(const Delay &delay,
+ const EarlyLate *early_late,
+ const StaState *sta,
+ int digits);
+const Delay &
+delayInitValue(const MinMax *min_max);
+bool
+delayIsInitValue(const Delay &delay,
+ const MinMax *min_max);
+bool
+fuzzyZero(const Delay &delay);
+bool
+fuzzyEqual(const Delay &delay1,
+ const Delay &delay2);
+bool
+fuzzyLess(const Delay &delay1,
+ const Delay &delay2);
+bool
+fuzzyLess(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max);
+bool
+fuzzyLessEqual(const Delay &delay1,
+ const Delay &delay2);
+bool
+fuzzyLessEqual(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max);
+bool
+fuzzyGreater(const Delay &delay1,
+ const Delay &delay2);
+bool
+fuzzyGreaterEqual(const Delay &delay1,
+ const Delay &delay2);
+bool
+fuzzyGreaterEqual(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max);
+bool
+fuzzyGreater(const Delay &delay1,
+ const Delay &delay2,
+ const MinMax *min_max);
+float
+delayRatio(const Delay &delay1,
+ const Delay &delay2);
+
+} // namespace
+#endif
diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc
index ff092c87..b18c470f 100644
--- a/graph/DelayNormal2.cc
+++ b/graph/DelayNormal2.cc
@@ -25,7 +25,7 @@
#include "Delay.hh"
// SSTA compilation.
-#if SSTA
+#if (SSTA == 2)
namespace sta {