test: Add comprehensive test infrastructure and test cases across all OpenSTA modules

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
This commit is contained in:
Jaehyun Kim 2026-02-27 12:59:25 +09:00
parent 8e08483e0e
commit 92bb9b8ec9
164 changed files with 2627706 additions and 37 deletions

2
.gitignore vendored
View File

@ -12,6 +12,7 @@ Makefile
gmon.out
cmake-build-debug
coverage-output
build
pvt
@ -21,6 +22,7 @@ examples/gcd_tb
doc/._Sta.docx
test/results
*/test/results
# ngspice turd
test/b3v3_1check.log

View File

@ -646,3 +646,44 @@ add_custom_command(
COMMAND ${STA_HOME}/etc/FindMessages.tcl > ${STA_HOME}/doc/messages.txt || true
WORKING_DIRECTORY ${STA_HOME}
)
################################################################
# Tests
################################################################
option(BUILD_TESTS "Build unit tests" ON)
if(BUILD_TESTS)
enable_testing()
find_package(GTest REQUIRED)
include(GoogleTest)
# Helper: register a list of Tcl tests for a module.
# Usage:
# sta_module_tests("search" TESTS timing analysis ...)
function(sta_module_tests module_name)
cmake_parse_arguments(ARG "" "" "TESTS" ${ARGN})
foreach(test_name ${ARG_TESTS})
add_test(
NAME tcl.${module_name}.${test_name}
COMMAND bash ${STA_HOME}/test/regression.sh $<TARGET_FILE:sta> ${module_name}_${test_name}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
set_tests_properties(tcl.${module_name}.${test_name} PROPERTIES LABELS "tcl;module_${module_name}")
endforeach()
endfunction()
add_subdirectory(test)
# Per-module tests
add_subdirectory(util/test)
add_subdirectory(liberty/test)
add_subdirectory(graph/test)
add_subdirectory(network/test)
add_subdirectory(sdc/test)
add_subdirectory(sdf/test)
add_subdirectory(dcalc/test)
add_subdirectory(search/test)
add_subdirectory(parasitics/test)
add_subdirectory(power/test)
add_subdirectory(verilog/test)
add_subdirectory(spice/test)
endif()

View File

@ -0,0 +1 @@
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestFindRoot TestFindRoot.cc)
target_link_libraries(TestFindRoot
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestFindRoot PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestFindRoot
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_dcalc"
)

View File

@ -0,0 +1,672 @@
#include <gtest/gtest.h>
#include <cmath>
#include <functional>
#include "dcalc/FindRoot.hh"
namespace sta {
class FindRootTest : public ::testing::Test {};
////////////////////////////////////////////////////////////////
// Original 7 tests
////////////////////////////////////////////////////////////////
// Test finding root of f(x) = x^2 - 4 (root at x=2)
TEST_F(FindRootTest, QuadraticPositiveRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 4.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 1.0, 3.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0, 1e-8);
}
// Test finding root of f(x) = x^2 - 4 (root at x=-2)
TEST_F(FindRootTest, QuadraticNegativeRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 4.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, -3.0, -1.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, -2.0, 1e-8);
}
// Test finding root of f(x) = x - 1 (linear, root at x=1)
TEST_F(FindRootTest, LinearRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 1.0;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, 0.0, 2.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 1.0, 1e-8);
}
// Test finding root of f(x) = sin(x) near pi
TEST_F(FindRootTest, SinRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = sin(x);
dy = cos(x);
};
bool fail = false;
double root = findRoot(func, 2.5, 3.8, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, M_PI, 1e-6);
}
// Test finding root of f(x) = e^x - 2 (root at x=ln(2))
TEST_F(FindRootTest, ExponentialRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = exp(x) - 2.0;
dy = exp(x);
};
bool fail = false;
double root = findRoot(func, 0.0, 1.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, log(2.0), 1e-8);
}
// Test with tight tolerance
TEST_F(FindRootTest, TightTolerance) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 2.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 1.0, 2.0, 1e-14, 200, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, sqrt(2.0), 1e-12);
}
// Test the 4-argument version with pre-computed y values
TEST_F(FindRootTest, WithPrecomputedY) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 9.0;
dy = 2.0 * x;
};
bool fail = false;
// x1=2, y1=4-9=-5, x2=4, y2=16-9=7
double root = findRoot(func, 2.0, -5.0, 4.0, 7.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 3.0, 1e-8);
}
////////////////////////////////////////////////////////////////
// Tolerance edge cases
////////////////////////////////////////////////////////////////
// Very tight tolerance: 1e-15 (near machine epsilon)
TEST_F(FindRootTest, VeryTightTolerance) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 5.0;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, 3.0, 7.0, 1e-15, 500, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 5.0, 1e-13);
}
// Very loose tolerance: 1e-1
TEST_F(FindRootTest, LooseTolerance) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 25.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 3.0, 7.0, 1e-1, 100, fail);
EXPECT_FALSE(fail);
// With 10% relative tolerance, result should still be in the right ballpark
EXPECT_NEAR(root, 5.0, 0.6);
}
// Zero tolerance: convergence check becomes abs(dx) <= 0, which is only
// satisfied when dx is exactly 0. Likely hits max_iter and fails.
TEST_F(FindRootTest, ZeroTolerance) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 3.0;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, 1.0, 5.0, 0.0, 100, fail);
// May or may not converge -- for a linear function Newton converges in 1 step
// so dx can be exactly 0. Accept either outcome.
if (!fail) {
EXPECT_NEAR(root, 3.0, 1e-10);
}
}
////////////////////////////////////////////////////////////////
// Iteration limit edge cases
////////////////////////////////////////////////////////////////
// Only 1 iteration allowed
TEST_F(FindRootTest, OneIteration) {
ASSERT_NO_THROW(( [&](){
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 4.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 1.0, 3.0, 1e-10, 1, fail);
// With only 1 iteration, a quadratic likely won't converge to tight tol
// The algorithm may or may not fail depending on initial bisection step
// Root should still be a finite number within the bracket
EXPECT_GE(root, 1.0);
EXPECT_LE(root, 3.0);
}() ));
}
// Two iterations
TEST_F(FindRootTest, TwoIterations) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 7.0;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, 5.0, 9.0, 1e-10, 2, fail);
// Linear function: Newton should converge very fast
// After the initial midpoint (7.0), Newton step should nail it
if (!fail) {
EXPECT_NEAR(root, 7.0, 1e-6);
}
}
// Zero max iterations: the for-loop body never executes, so fail is set to true
TEST_F(FindRootTest, ZeroMaxIterations) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 1.0;
dy = 1.0;
};
bool fail = false;
findRoot(func, 0.0, 2.0, 1e-10, 0, fail);
EXPECT_TRUE(fail);
}
// Large max_iter (should still converge quickly and not hang)
TEST_F(FindRootTest, LargeMaxIter) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 16.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 1.0, 10.0, 1e-12, 10000, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 4.0, 1e-10);
}
////////////////////////////////////////////////////////////////
// Special function types
////////////////////////////////////////////////////////////////
// Cubic: f(x) = x^3 - 8 (root at x=2)
TEST_F(FindRootTest, CubicRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x * x - 8.0;
dy = 3.0 * x * x;
};
bool fail = false;
double root = findRoot(func, 1.0, 3.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0, 1e-8);
}
// Quartic: f(x) = x^4 - 16 (root at x=2)
TEST_F(FindRootTest, QuarticRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x * x * x - 16.0;
dy = 4.0 * x * x * x;
};
bool fail = false;
double root = findRoot(func, 1.0, 3.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0, 1e-8);
}
// Exponential: f(x) = e^x - 10 (root at x=ln(10))
TEST_F(FindRootTest, ExponentialRoot2) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = exp(x) - 10.0;
dy = exp(x);
};
bool fail = false;
double root = findRoot(func, 1.0, 4.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, log(10.0), 1e-8);
}
// Square root function: f(x) = sqrt(x) - 3, root at x=9
// Derivative: 1/(2*sqrt(x))
TEST_F(FindRootTest, SqrtFunctionRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = sqrt(x) - 3.0;
dy = 0.5 / sqrt(x);
};
bool fail = false;
double root = findRoot(func, 1.0, 20.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 9.0, 1e-6);
}
////////////////////////////////////////////////////////////////
// Near-zero roots
////////////////////////////////////////////////////////////////
// f(x) = x - 1e-10 (root very close to zero)
// Note: convergence check is abs(dx) <= x_tol * abs(root).
// When root is near zero, the relative tolerance is very tight.
// This may require many iterations or not converge.
TEST_F(FindRootTest, NearZeroRootLinear) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 1e-10;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, -1.0, 1.0, 1e-6, 200, fail);
// Newton on a linear function converges in 1-2 steps regardless of root location
if (!fail) {
EXPECT_NEAR(root, 1e-10, 1e-6);
}
}
// f(x) = x (root exactly at zero)
// Convergence test: abs(dx) <= x_tol * abs(root) = x_tol * 0 = 0
// Will likely hit max_iter because relative tolerance at root=0 requires dx=0 exactly
TEST_F(FindRootTest, RootExactlyAtZero) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, -1.0, 1.0, 1e-10, 200, fail);
// Even if fail is true, root should be very close to 0
EXPECT_NEAR(root, 0.0, 1e-6);
}
////////////////////////////////////////////////////////////////
// Negative domain
////////////////////////////////////////////////////////////////
// Root in deeply negative domain: f(x) = x + 100, root at x=-100
TEST_F(FindRootTest, NegativeDomainRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x + 100.0;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, -200.0, 0.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, -100.0, 1e-6);
}
// Both bracket endpoints negative: f(x) = x^2 - 1, root at x=-1
TEST_F(FindRootTest, NegativeBracketRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 1.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, -2.0, -0.5, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, -1.0, 1e-8);
}
////////////////////////////////////////////////////////////////
// Trigonometric functions
////////////////////////////////////////////////////////////////
// sin(x) root at x=0 (bracket [-1, 1])
TEST_F(FindRootTest, SinRootAtZero) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = sin(x);
dy = cos(x);
};
bool fail = false;
double root = findRoot(func, -1.0, 1.0, 1e-10, 100, fail);
// Root at 0 has the relative-tolerance issue, but Newton converges fast for sin
EXPECT_NEAR(root, 0.0, 1e-4);
}
// sin(x) root at x=2*pi (bracket [5.5, 7.0])
TEST_F(FindRootTest, SinRootAt2Pi) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = sin(x);
dy = cos(x);
};
bool fail = false;
double root = findRoot(func, 5.5, 7.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0 * M_PI, 1e-6);
}
// cos(x) root at x=pi/2
TEST_F(FindRootTest, CosRootAtPiOver2) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = cos(x);
dy = -sin(x);
};
bool fail = false;
double root = findRoot(func, 1.0, 2.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, M_PI / 2.0, 1e-6);
}
////////////////////////////////////////////////////////////////
// Multiple roots nearby
////////////////////////////////////////////////////////////////
// f(x) = (x-1)(x-2) = x^2 - 3x + 2, roots at x=1 and x=2
// Bracket [0.5, 1.5] should find x=1
TEST_F(FindRootTest, MultipleRootsFindFirst) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = (x - 1.0) * (x - 2.0);
dy = 2.0 * x - 3.0;
};
bool fail = false;
double root = findRoot(func, 0.5, 1.5, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 1.0, 1e-8);
}
// Same function, bracket [1.5, 2.5] should find x=2
TEST_F(FindRootTest, MultipleRootsFindSecond) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = (x - 1.0) * (x - 2.0);
dy = 2.0 * x - 3.0;
};
bool fail = false;
double root = findRoot(func, 1.5, 2.5, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0, 1e-8);
}
////////////////////////////////////////////////////////////////
// Discontinuous derivative (sharp corner)
////////////////////////////////////////////////////////////////
// f(x) = |x| - 1 with piecewise derivative.
// Root at x=1 (bracket [0.5, 2.0] avoids the corner at 0)
TEST_F(FindRootTest, AbsValueRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = fabs(x) - 1.0;
dy = (x >= 0.0) ? 1.0 : -1.0;
};
bool fail = false;
double root = findRoot(func, 0.5, 2.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 1.0, 1e-8);
}
// f(x) = |x| - 1, root at x=-1
TEST_F(FindRootTest, AbsValueNegativeRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = fabs(x) - 1.0;
dy = (x >= 0.0) ? 1.0 : -1.0;
};
bool fail = false;
double root = findRoot(func, -2.0, -0.5, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, -1.0, 1e-8);
}
////////////////////////////////////////////////////////////////
// Very flat function (slow convergence)
////////////////////////////////////////////////////////////////
// f(x) = (x - 3)^5 has a repeated root at x=3 where the derivative is also
// zero. Newton-Raphson divides by dy which becomes 0, producing NaN.
// The algorithm is expected to fail on this degenerate case.
TEST_F(FindRootTest, FlatFifthOrderRootFails) {
FindRootFunc func = [](double x, double &y, double &dy) {
double d = x - 3.0;
double d2 = d * d;
double d4 = d2 * d2;
y = d4 * d; // (x-3)^5
dy = 5.0 * d4; // 5*(x-3)^4
};
bool fail = false;
findRoot(func, 2.0, 4.0, 1e-6, 500, fail);
// The algorithm is expected to fail because dy -> 0 at the root
EXPECT_TRUE(fail);
}
// A function that is very flat near the root but still has nonzero derivative
// at the root: f(x) = sinh(x - 3) which is ~0 near x=3 but never has dy=0.
// sinh is flat near 0 (sinh(e) ~ e for small e) but derivative cosh(e) >= 1.
TEST_F(FindRootTest, FlatSinhRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = sinh(x - 3.0);
dy = cosh(x - 3.0);
};
bool fail = false;
double root = findRoot(func, 2.0, 4.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 3.0, 1e-6);
}
////////////////////////////////////////////////////////////////
// Very steep function (fast convergence)
////////////////////////////////////////////////////////////////
// f(x) = 1000*(x - 5), root at x=5. Very steep gradient.
TEST_F(FindRootTest, SteepLinearRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = 1000.0 * (x - 5.0);
dy = 1000.0;
};
bool fail = false;
double root = findRoot(func, 3.0, 7.0, 1e-12, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 5.0, 1e-10);
}
// f(x) = 1e6 * (x - 2), very steep
TEST_F(FindRootTest, VerySteepLinearRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = 1e6 * (x - 2.0);
dy = 1e6;
};
bool fail = false;
double root = findRoot(func, 1.0, 3.0, 1e-14, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0, 1e-12);
}
////////////////////////////////////////////////////////////////
// Large bracket
////////////////////////////////////////////////////////////////
// f(x) = x - 42, bracket [-1000, 1000]
TEST_F(FindRootTest, LargeBracket) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 42.0;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, -1000.0, 1000.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 42.0, 1e-6);
}
// Quadratic with large bracket: f(x) = x^2 - 100, root at 10
TEST_F(FindRootTest, LargeBracketQuadratic) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 100.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 1.0, 1000.0, 1e-10, 200, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 10.0, 1e-6);
}
////////////////////////////////////////////////////////////////
// Small bracket
////////////////////////////////////////////////////////////////
// f(x) = x - 1.0, bracket [0.999999, 1.000001] (very tight bracket around root)
TEST_F(FindRootTest, SmallBracket) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 1.0;
dy = 1.0;
};
bool fail = false;
double root = findRoot(func, 0.999999, 1.000001, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 1.0, 1e-6);
}
// Quadratic with very small bracket around root=2
TEST_F(FindRootTest, SmallBracketQuadratic) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 4.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 1.9999, 2.0001, 1e-12, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0, 1e-8);
}
////////////////////////////////////////////////////////////////
// Both overloads tested together
////////////////////////////////////////////////////////////////
// Compare 2-arg and 4-arg overloads produce same result
TEST_F(FindRootTest, OverloadsProduceSameResult) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x * x - 27.0;
dy = 3.0 * x * x;
};
bool fail_2arg = false;
double root_2arg = findRoot(func, 2.0, 4.0, 1e-12, 100, fail_2arg);
// Pre-compute y values for 4-arg version
double y1 = 2.0 * 2.0 * 2.0 - 27.0; // 8 - 27 = -19
double y2 = 4.0 * 4.0 * 4.0 - 27.0; // 64 - 27 = 37
bool fail_4arg = false;
double root_4arg = findRoot(func, 2.0, y1, 4.0, y2, 1e-12, 100, fail_4arg);
EXPECT_FALSE(fail_2arg);
EXPECT_FALSE(fail_4arg);
EXPECT_NEAR(root_2arg, 3.0, 1e-10);
EXPECT_NEAR(root_4arg, 3.0, 1e-10);
EXPECT_NEAR(root_2arg, root_4arg, 1e-14);
}
// 4-arg overload: x1 endpoint is exact root (y1 == 0)
TEST_F(FindRootTest, FourArgX1IsRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 5.0;
dy = 1.0;
};
bool fail = false;
// y1 = 5 - 5 = 0
double root = findRoot(func, 5.0, 0.0, 8.0, 3.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_DOUBLE_EQ(root, 5.0);
}
// 4-arg overload: x2 endpoint is exact root (y2 == 0)
TEST_F(FindRootTest, FourArgX2IsRoot) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 5.0;
dy = 1.0;
};
bool fail = false;
// y2 = 5 - 5 = 0
double root = findRoot(func, 2.0, -3.0, 5.0, 0.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_DOUBLE_EQ(root, 5.0);
}
////////////////////////////////////////////////////////////////
// Same-sign y values (should fail)
////////////////////////////////////////////////////////////////
// Both endpoints positive: should fail
TEST_F(FindRootTest, BothEndpointsPositiveFails) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x + 1.0; // Always positive, no real root
dy = 2.0 * x;
};
bool fail = false;
findRoot(func, 1.0, 3.0, 1e-10, 100, fail);
EXPECT_TRUE(fail);
}
// Both endpoints negative: should fail
TEST_F(FindRootTest, BothEndpointsNegativeFails) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = -x * x - 1.0; // Always negative
dy = -2.0 * x;
};
bool fail = false;
findRoot(func, -3.0, 3.0, 1e-10, 100, fail);
EXPECT_TRUE(fail);
}
// 4-arg version: same-sign y values
TEST_F(FindRootTest, FourArgSameSignFails) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x;
dy = 2.0 * x;
};
bool fail = false;
// Both y values positive
findRoot(func, 1.0, 1.0, 2.0, 4.0, 1e-10, 100, fail);
EXPECT_TRUE(fail);
}
////////////////////////////////////////////////////////////////
// Symmetry test
////////////////////////////////////////////////////////////////
// f(x) = x^2 - 4: bracket [0, 3] finds +2, bracket [-3, 0] finds -2
TEST_F(FindRootTest, SymmetryPositiveBracket) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 4.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, 0.5, 3.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 2.0, 1e-8);
}
TEST_F(FindRootTest, SymmetryNegativeBracket) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x * x - 4.0;
dy = 2.0 * x;
};
bool fail = false;
double root = findRoot(func, -3.0, -0.5, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, -2.0, 1e-8);
}
////////////////////////////////////////////////////////////////
// Swapped bracket order (x1 > x2)
////////////////////////////////////////////////////////////////
// The algorithm should work regardless of bracket order
TEST_F(FindRootTest, SwappedBracketOrder) {
FindRootFunc func = [](double x, double &y, double &dy) {
y = x - 3.0;
dy = 1.0;
};
bool fail = false;
// x1=5 > x2=1 (reversed order)
double root = findRoot(func, 5.0, 1.0, 1e-10, 100, fail);
EXPECT_FALSE(fail);
EXPECT_NEAR(root, 3.0, 1e-8);
}
} // namespace sta

1
dcalc/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
dcalc/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

127
etc/Build.sh Executable file
View File

@ -0,0 +1,127 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2025, The OpenROAD Authors
set -euo pipefail
DIR="$(dirname $(readlink -f $0))"
cd "$DIR/../"
# default values, can be overwritten by cmdline args
buildDir="build"
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
numThreads=$(nproc --all)
elif [[ "$OSTYPE" == "darwin"* ]]; then
numThreads=$(sysctl -n hw.ncpu)
else
cat << EOF
WARNING: Unsupported OSTYPE: cannot determine number of host CPUs"
Defaulting to 2 threads. Use -threads=N to use N threads"
EOF
numThreads=2
fi
cmakeOptions=""
cleanBefore=no
compiler=gcc
_help() {
cat <<EOF
usage: $0 [OPTIONS]
Build OpenSTA from source.
OPTIONS:
-cmake='-<key>=<value> ...' User defined cmake options
Note: use single quote after
-cmake= and double quotes if
<key> has multiple <values>
e.g.: -cmake='-DFLAGS="-a -b"'
-compiler=COMPILER_NAME Compiler name: gcc or clang
Default: gcc
-dir=PATH Path to store build files.
Default: ./build
-coverage Enable cmake coverage options
-clean Remove build dir before compile
-threads=NUM_THREADS Number of threads to use during
compile. Default: \`nproc\` on linux
or \`sysctl -n hw.ncpu\` on macOS
-O0 Disable optimizations for accurate
coverage measurement
-help Shows this message
EOF
exit "${1:-1}"
}
while [ "$#" -gt 0 ]; do
case "${1}" in
-h|-help)
_help 0
;;
-coverage )
cmakeOptions+=" -DCMAKE_BUILD_TYPE=Debug"
cmakeOptions+=" -DCMAKE_CXX_FLAGS='--coverage'"
cmakeOptions+=" -DCMAKE_EXE_LINKER_FLAGS='--coverage'"
;;
-O0 )
cmakeOptions+=" -DCMAKE_CXX_FLAGS_DEBUG='-g -O0'"
;;
-cmake=*)
cmakeOptions+=" ${1#*=}"
;;
-clean )
cleanBefore=yes
;;
-compiler=*)
compiler="${1#*=}"
;;
-dir=* )
buildDir="${1#*=}"
;;
-threads=* )
numThreads="${1#*=}"
;;
-compiler | -cmake | -dir | -threads )
echo "${1} requires an argument" >&2
_help
;;
*)
echo "unknown option: ${1}" >&2
_help
;;
esac
shift 1
done
case "${compiler}" in
"gcc" )
export CC="$(command -v gcc)"
export CXX="$(command -v g++)"
;;
"clang" )
export CC="$(command -v clang)"
export CXX="$(command -v clang++)"
;;
*)
echo "Compiler $compiler not supported. Use gcc or clang." >&2
_help 1
esac
if [[ -z "${CC}" || -z "${CXX}" ]]; then
echo "Compiler $compiler not installed." >&2
_help 1
fi
if [[ "${cleanBefore}" == "yes" ]]; then
rm -rf "${buildDir}"
fi
mkdir -p "${buildDir}"
echo "[INFO] Compiler: ${compiler} (${CC})"
echo "[INFO] Build dir: ${buildDir}"
echo "[INFO] Using ${numThreads} threads."
eval cmake "${cmakeOptions}" -B "${buildDir}" .
eval time cmake --build "${buildDir}" -j "${numThreads}"

120
etc/CodeCoverage.sh Executable file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2025, The OpenROAD Authors
# Generate an lcov/genhtml code coverage report for OpenSTA.
# Requires a coverage build: ./etc/Build.sh -coverage
#
# Usage:
# ./etc/CodeCoverage.sh Run all tests, generate report
# ./etc/CodeCoverage.sh -tcl-only Run only Tcl tests (skip C++ unit tests)
set -euo pipefail
cd "$(dirname $(readlink -f $0))/../"
buildDir="build"
reportDir="coverage-output"
tclOnly=no
_help() {
cat <<EOF
usage: $0 [OPTIONS]
Generate an lcov/genhtml code coverage report for OpenSTA.
Requires a coverage build first: ./etc/Build.sh -coverage
OPTIONS:
-tcl-only Run only Tcl tests (skip C++ unit tests)
-dir=PATH Build directory. Default: ./build
-help Shows this message
OUTPUT:
coverage-output/ HTML coverage report
coverage-output/index.html Main report page
EOF
exit "${1:-1}"
}
while [ "$#" -gt 0 ]; do
case "${1}" in
-h|-help)
_help 0
;;
-tcl-only)
tclOnly=yes
;;
-dir=*)
buildDir="${1#*=}"
;;
-dir )
echo "${1} requires an argument" >&2
_help
;;
*)
echo "unknown option: ${1}" >&2
_help
;;
esac
shift 1
done
if [[ ! -d "${buildDir}" ]]; then
echo "Build directory '${buildDir}' not found." >&2
echo "Run ./etc/Build.sh -coverage first." >&2
exit 1
fi
# Common lcov flags to suppress all known warnings:
# mismatch - GCC/GoogleTest macro function range mismatches
# gcov - unexecuted blocks on non-branch lines (GCC optimizer artifacts)
# source - source file newer than .gcno notes file (stale build artifacts)
# Double-specification (X,X) suppresses the warning output entirely.
LCOV_IGNORE="--ignore-errors mismatch,mismatch,gcov,gcov,source,source,unused,unused,negative,negative"
# Clear stale coverage data before test execution.
# Old .gcda files from previous runs can cause gcov checksum mismatch noise.
find "${buildDir}" -name '*.gcda' -delete
# Step 1: Run tests
if [[ "${tclOnly}" == "yes" ]]; then
echo "[INFO] Running Tcl tests only..."
ctest --test-dir "${buildDir}" -L tcl -j $(nproc) --output-on-failure || true
else
echo "[INFO] Running all tests..."
ctest --test-dir "${buildDir}" -j $(nproc) --output-on-failure || true
fi
# Step 2: Capture coverage
echo "[INFO] Capturing coverage data..."
lcov --capture \
-d "${buildDir}" \
-o "${buildDir}/coverage.info" \
--quiet \
${LCOV_IGNORE}
# Step 3: Filter system/build/test dirs
lcov --remove "${buildDir}/coverage.info" \
'/usr/*' \
'*/build/*' \
'*/test/*' \
-o "${buildDir}/filtered.info" \
--quiet \
${LCOV_IGNORE}
# Step 4: Generate HTML report
GENHTML_IGNORE="--ignore-errors unmapped,unmapped,inconsistent,inconsistent,corrupt,corrupt,negative,negative,empty,empty,format,format,mismatch,mismatch,source,source"
mkdir -p "${reportDir}"
genhtml "${buildDir}/filtered.info" \
--output-directory "${reportDir}" \
--quiet \
${GENHTML_IGNORE} || true
echo ""
echo "=== Coverage report generated ==="
echo "Open $(pwd)/${reportDir}/index.html in a browser to view."
echo ""
lcov --summary "${buildDir}/filtered.info" ${LCOV_IGNORE} 2>&1 || true

View File

@ -0,0 +1,6 @@
sta_module_tests("graph"
TESTS
make_verify
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestGraph TestGraph.cc)
target_link_libraries(TestGraph
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestGraph PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestGraph
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_graph"
)

2026
graph/test/cpp/TestGraph.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
No paths found.

View File

@ -0,0 +1,10 @@
# Read liberty and design, make graph, verify
read_liberty ../../test/nangate45/Nangate45_typ.lib
read_verilog graph_test1.v
link_design graph_test1
# Creating the timing graph implicitly tests graph construction
create_clock -name clk -period 10 [get_ports clk]
# report_checks exercises the graph
report_checks -from [get_ports d] -to [get_ports q]

8
graph/test/graph_test1.v Normal file
View File

@ -0,0 +1,8 @@
module graph_test1 (clk, d, q);
input clk, d;
output q;
wire n1;
DFF_X1 reg1 (.D(d), .CK(clk), .Q(n1));
DFF_X1 reg2 (.D(n1), .CK(clk), .Q(q));
endmodule

14
graph/test/graph_test2.v Normal file
View File

@ -0,0 +1,14 @@
module graph_test2 (clk, d1, d2, en, q1, q2);
input clk, d1, d2, en;
output q1, q2;
wire n1, n2, n3, n4, n5, n6;
BUF_X1 buf1 (.A(d1), .Z(n1));
BUF_X2 buf2 (.A(d2), .Z(n2));
INV_X1 inv1 (.A(n1), .ZN(n3));
AND2_X1 and1 (.A1(n3), .A2(en), .ZN(n4));
OR2_X1 or1 (.A1(n2), .A2(n4), .ZN(n5));
BUF_X1 buf3 (.A(n5), .Z(n6));
DFF_X1 reg1 (.D(n4), .CK(clk), .Q(q1));
DFF_X1 reg2 (.D(n6), .CK(clk), .Q(q2));
endmodule

34
graph/test/graph_test3.v Normal file
View File

@ -0,0 +1,34 @@
// Larger design for graph operations testing: more cell types, fan-in/fan-out,
// multiple clock domains, and reconvergent paths.
module graph_test3 (clk1, clk2, rst, d1, d2, d3, d4, q1, q2, q3);
input clk1, clk2, rst, d1, d2, d3, d4;
output q1, q2, q3;
wire n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12;
// Input stage: buffers and inverters
BUF_X1 buf1 (.A(d1), .Z(n1));
BUF_X2 buf2 (.A(d2), .Z(n2));
INV_X1 inv1 (.A(d3), .ZN(n3));
INV_X2 inv2 (.A(d4), .ZN(n4));
// Middle stage: logic gates
AND2_X1 and1 (.A1(n1), .A2(n2), .ZN(n5));
OR2_X1 or1 (.A1(n3), .A2(n4), .ZN(n6));
NAND2_X1 nand1 (.A1(n5), .A2(n6), .ZN(n7));
NOR2_X1 nor1 (.A1(n1), .A2(n3), .ZN(n8));
// Reconvergent fan-out
AND2_X2 and2 (.A1(n7), .A2(n8), .ZN(n9));
OR2_X2 or2 (.A1(n7), .A2(n8), .ZN(n10));
// Clock domain 1 registers
DFF_X1 reg1 (.D(n9), .CK(clk1), .Q(n11));
DFF_X1 reg2 (.D(n10), .CK(clk1), .Q(q1));
// Clock domain 2 register (cross-domain)
DFF_X1 reg3 (.D(n11), .CK(clk2), .Q(n12));
BUF_X1 buf3 (.A(n12), .Z(q2));
// Combinational output
BUF_X4 buf4 (.A(n7), .Z(q3));
endmodule

1
graph/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
graph/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

View File

@ -0,0 +1,6 @@
sta_module_tests("liberty"
TESTS
read_nangate
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestLibertyClasses TestLibertyClasses.cc)
target_link_libraries(TestLibertyClasses
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestLibertyClasses PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestLibertyClasses
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_liberty"
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,165 @@
Cell INV_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 1.55-1.70
ZN output function=!A
Cell BUF_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 0.88-0.97
Z output function=A
Cell NAND2_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A1 input 1.53-1.60
A2 input 1.50-1.66
ZN output function=!(A1*A2)
Cell NOR2_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A1 input 1.41-1.71
A2 input 1.56-1.65
ZN output function=!(A1+A2)
Cell AND2_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A1 input 0.87-0.92
A2 input 0.89-0.97
ZN output function=A1*A2
Cell OR2_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A1 input 0.79-0.95
A2 input 0.90-0.94
ZN output function=A1+A2
Cell MUX2_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 0.91-0.95
B input 0.90-0.94
S input 1.81-1.92
Z output function=(S*B)+(A*!S)
Cell DFF_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
IQ internal
IQN internal
VDD power
VSS ground
D input 1.06-1.14
CK input 0.86-0.95
Q output function=IQ
QN output function=IQN
Cell DFFR_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
IQ internal
IQN internal
VDD power
VSS ground
D input 1.05-1.13
RN input 1.74-1.78
CK input 0.88-0.98
Q output function=IQ
QN output function=IQN
Cell DFFS_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
IQ internal
IQN internal
VDD power
VSS ground
D input 1.09-1.16
SN input 1.33-1.36
CK input 0.88-0.97
Q output function=IQ
QN output function=IQN
Cell DFFRS_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
IQ internal
IQN internal
VDD power
VSS ground
D input 1.08-1.15
RN input 1.38-1.41
SN input 2.10-2.21
CK input 0.87-0.96
Q output function=IQ
QN output function=IQN
Cell TLAT_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
IQ internal
IQN internal
VDD power
VSS ground
D input 1.07-1.14
G input 0.92-1.02
OE input 1.42-1.50
Q tristate enable=OE function=IQ 0.79-0.79
Cell AOI21_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 1.54-1.63
B1 input 1.45-1.65
B2 input 1.41-1.68
ZN output function=!(A+(B1*B2))
Cell OAI21_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 1.52-1.67
B1 input 1.46-1.66
B2 input 1.56-1.57
ZN output function=!(A*(B1+B2))
Cell HA_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 3.06-3.19
B input 3.34-3.45
CO output function=A*B
S output function=A^B
Cell FA_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 3.61-3.75
B input 3.40-3.47
CI input 2.66-2.76
CO output function=(A*B)+(CI*(A+B))
S output function=CI^(A^B)
Cell CLKBUF_X1
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 0.70-0.78
Z output function=A
Cell CLKBUF_X2
Library NangateOpenCellLibrary
File ../../test/nangate45/Nangate45_typ.lib
VDD power
VSS ground
A input 1.24-1.41
Z output function=A

View File

@ -0,0 +1,276 @@
# Test Nangate45 library reading and cell/pin queries for code coverage
read_liberty ../../test/nangate45/Nangate45_typ.lib
############################################################
# Library queries
############################################################
set lib [get_libs NangateOpenCellLibrary]
if { $lib == "" } {
puts "FAIL: library not found"
exit 1
}
############################################################
# Inverter cells
############################################################
set inv1 [get_lib_cells NangateOpenCellLibrary/INV_X1]
if { $inv1 == "" } {
puts "FAIL: INV_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/INV_X1
set inv_pins [get_lib_pins NangateOpenCellLibrary/INV_X1/*]
if { [llength $inv_pins] != 2 } {
error "expected 2 pins on INV_X1, found [llength $inv_pins]"
}
# Other inverter sizes
foreach sz {X2 X4 X8 X16 X32} {
set cell [get_lib_cells NangateOpenCellLibrary/INV_$sz]
if { $cell == "" } {
puts "FAIL: INV_$sz not found"
exit 1
}
}
############################################################
# Buffer cells
############################################################
set buf1 [get_lib_cells NangateOpenCellLibrary/BUF_X1]
if { $buf1 == "" } {
puts "FAIL: BUF_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/BUF_X1
set buf_pins [get_lib_pins NangateOpenCellLibrary/BUF_X1/*]
if { [llength $buf_pins] != 2 } {
error "expected 2 pins on BUF_X1, found [llength $buf_pins]"
}
foreach sz {X2 X4 X8 X16 X32} {
set cell [get_lib_cells NangateOpenCellLibrary/BUF_$sz]
if { $cell == "" } {
puts "FAIL: BUF_$sz not found"
exit 1
}
}
############################################################
# NAND cells
############################################################
set nand2 [get_lib_cells NangateOpenCellLibrary/NAND2_X1]
if { $nand2 == "" } {
puts "FAIL: NAND2_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/NAND2_X1
set nand_pins [get_lib_pins NangateOpenCellLibrary/NAND2_X1/*]
if { [llength $nand_pins] != 3 } {
error "expected 3 pins on NAND2_X1, found [llength $nand_pins]"
}
foreach cell_name {NAND2_X2 NAND2_X4 NAND3_X1 NAND3_X2 NAND4_X1} {
set cell [get_lib_cells NangateOpenCellLibrary/$cell_name]
if { $cell == "" } {
puts "FAIL: $cell_name not found"
exit 1
}
}
############################################################
# NOR cells
############################################################
set nor2 [get_lib_cells NangateOpenCellLibrary/NOR2_X1]
if { $nor2 == "" } {
puts "FAIL: NOR2_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/NOR2_X1
foreach cell_name {NOR2_X2 NOR2_X4 NOR3_X1 NOR4_X1} {
set cell [get_lib_cells NangateOpenCellLibrary/$cell_name]
if { $cell == "" } {
puts "FAIL: $cell_name not found"
exit 1
}
}
############################################################
# AND cells
############################################################
set and2 [get_lib_cells NangateOpenCellLibrary/AND2_X1]
if { $and2 == "" } {
puts "FAIL: AND2_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/AND2_X1
foreach cell_name {AND2_X2 AND2_X4 AND3_X1 AND4_X1} {
set cell [get_lib_cells NangateOpenCellLibrary/$cell_name]
if { $cell == "" } {
puts "FAIL: $cell_name not found"
exit 1
}
}
############################################################
# OR cells
############################################################
set or2 [get_lib_cells NangateOpenCellLibrary/OR2_X1]
if { $or2 == "" } {
puts "FAIL: OR2_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/OR2_X1
foreach cell_name {OR2_X2 OR2_X4 OR3_X1 OR4_X1} {
set cell [get_lib_cells NangateOpenCellLibrary/$cell_name]
if { $cell == "" } {
puts "FAIL: $cell_name not found"
exit 1
}
}
############################################################
# MUX cells
############################################################
set mux [get_lib_cells NangateOpenCellLibrary/MUX2_X1]
if { $mux == "" } {
puts "FAIL: MUX2_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/MUX2_X1
############################################################
# DFF cells
############################################################
set dff [get_lib_cells NangateOpenCellLibrary/DFF_X1]
if { $dff == "" } {
puts "FAIL: DFF_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/DFF_X1
set dff_pins [get_lib_pins NangateOpenCellLibrary/DFF_X1/*]
# DFF with reset
set dffr [get_lib_cells NangateOpenCellLibrary/DFFR_X1]
if { $dffr == "" } {
puts "FAIL: DFFR_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/DFFR_X1
# DFF with set
set dffs [get_lib_cells NangateOpenCellLibrary/DFFS_X1]
if { $dffs == "" } {
puts "FAIL: DFFS_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/DFFS_X1
# DFF with reset and set
set dffrs [get_lib_cells NangateOpenCellLibrary/DFFRS_X1]
if { $dffrs == "" } {
puts "FAIL: DFFRS_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/DFFRS_X1
############################################################
# Latch (TLAT)
############################################################
set tlat [get_lib_cells NangateOpenCellLibrary/TLAT_X1]
if { $tlat == "" } {
puts "FAIL: TLAT_X1 not found"
exit 1
}
report_lib_cell NangateOpenCellLibrary/TLAT_X1
############################################################
# Complex cells: AOI, OAI, HA, FA
############################################################
report_lib_cell NangateOpenCellLibrary/AOI21_X1
report_lib_cell NangateOpenCellLibrary/OAI21_X1
report_lib_cell NangateOpenCellLibrary/HA_X1
report_lib_cell NangateOpenCellLibrary/FA_X1
############################################################
# get_lib_cells with pattern matching
############################################################
set all_inv [get_lib_cells NangateOpenCellLibrary/INV_*]
if { [llength $all_inv] < 6 } {
error "expected multiple INV_* cells, found [llength $all_inv]"
}
set all_buf [get_lib_cells NangateOpenCellLibrary/BUF_*]
if { [llength $all_buf] < 6 } {
error "expected multiple BUF_* cells, found [llength $all_buf]"
}
set all_dff [get_lib_cells NangateOpenCellLibrary/DFF*]
if { [llength $all_dff] < 4 } {
error "expected multiple DFF* cells, found [llength $all_dff]"
}
set all_cells [get_lib_cells NangateOpenCellLibrary/*]
if { [llength $all_cells] < 100 } {
error "expected full Nangate library cell list, found [llength $all_cells]"
}
############################################################
# get_lib_pins with patterns
############################################################
set all_inv_pins [get_lib_pins NangateOpenCellLibrary/INV_X1/*]
if { [llength $all_inv_pins] != 2 } {
error "expected 2 INV_X1 pins from wildcard, found [llength $all_inv_pins]"
}
set all_dff_pins [get_lib_pins NangateOpenCellLibrary/DFF_X1/*]
if { [llength $all_dff_pins] < 4 } {
error "expected DFF_X1 pins to include D/CK/Q(+variants), found [llength $all_dff_pins]"
}
set nand_a1 [get_lib_pins NangateOpenCellLibrary/NAND2_X1/A1]
if { [llength $nand_a1] != 1 } {
error "expected single NAND2_X1/A1 pin match"
}
############################################################
# Clock buffer
############################################################
report_lib_cell NangateOpenCellLibrary/CLKBUF_X1
report_lib_cell NangateOpenCellLibrary/CLKBUF_X2

1
liberty/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
liberty/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

View File

@ -0,0 +1,6 @@
sta_module_tests("network"
TESTS
query
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestNetwork TestNetwork.cc)
target_link_libraries(TestNetwork
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestNetwork PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestNetwork
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_network"
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
Cells: 3
Nets: 6
Ports: 4

View File

@ -0,0 +1,35 @@
# Read design and query network objects
read_liberty ../../test/nangate45/Nangate45_typ.lib
read_verilog network_test1.v
link_design network_test1
# Query cells
set cells [get_cells *]
puts "Cells: [llength $cells]"
if { [llength $cells] != 3 } {
puts "FAIL: expected 3 cells"
exit 1
}
# Query nets
set nets [get_nets *]
puts "Nets: [llength $nets]"
if { [llength $nets] == 0 } {
puts "FAIL: no nets found"
exit 1
}
# Query pins
set pins [get_pins buf1/*]
if { [llength $pins] == 0 } {
puts "FAIL: no pins found on buf1"
exit 1
}
# Query ports
set ports [get_ports *]
puts "Ports: [llength $ports]"
if { [llength $ports] != 4 } {
puts "FAIL: expected 4 ports"
exit 1
}

View File

@ -0,0 +1,9 @@
module network_test1 (clk, in1, in2, out1);
input clk, in1, in2;
output out1;
wire n1, n2;
BUF_X1 buf1 (.A(in1), .Z(n1));
AND2_X1 and1 (.A1(n1), .A2(in2), .ZN(n2));
DFF_X1 reg1 (.D(n2), .CK(clk), .Q(out1));
endmodule

1
network/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
network/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

View File

@ -0,0 +1,6 @@
sta_module_tests("parasitics"
TESTS
spef
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestParasitics TestParasitics.cc)
target_link_libraries(TestParasitics
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestParasitics PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestParasitics
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_parasitics"
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 13178, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 13211, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 13244, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 13277, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 13310, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 13343, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 13376, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 14772, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 14805, timing group from output port.
Warning 1212: ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz line 14838, timing group from output port.
r1q total_cap=1.3922564510505161e-14 pin_cap=5.225650124681606e-16 wire_cap=1.3399999392157882e-14
r2q total_cap=1.3977042281540768e-14 pin_cap=5.770419894103802e-16 wire_cap=1.3400000239190829e-14
u1z total_cap=1.3965708133673559e-14 pin_cap=5.65708000361848e-16 wire_cap=1.3400000239190829e-14
u2z total_cap=1.4021215896773027e-14 pin_cap=6.212170340107377e-16 wire_cap=1.3399998545124935e-14
No paths found.

View File

@ -0,0 +1,29 @@
# Test SPEF read and parasitics reporting
# reg1_asap7 uses ASAP7 cells
read_liberty ../../test/asap7/asap7sc7p5t_SEQ_RVT_FF_nldm_220123.lib
read_liberty ../../test/asap7/asap7sc7p5t_INVBUF_RVT_FF_nldm_220122.lib.gz
read_liberty ../../test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz
read_liberty ../../test/asap7/asap7sc7p5t_OA_RVT_FF_nldm_211120.lib.gz
read_liberty ../../test/asap7/asap7sc7p5t_AO_RVT_FF_nldm_211120.lib.gz
read_verilog ../../test/reg1_asap7.v
link_design top
create_clock -name clk1 -period 10 [get_ports clk1]
# Read SPEF
read_spef ../../test/reg1_asap7.spef
set corner [sta::cmd_scene]
foreach net_name {r1q r2q u1z u2z} {
set net [get_nets $net_name]
set total_cap [$net capacitance $corner "max"]
set pin_cap [$net pin_capacitance $corner "max"]
set wire_cap [$net wire_capacitance $corner "max"]
puts "$net_name total_cap=$total_cap pin_cap=$pin_cap wire_cap=$wire_cap"
if {$total_cap <= 0.0} {
error "expected positive capacitance on net $net_name after SPEF read"
}
}
report_checks -fields {slew cap input_pins fanout}

1
parasitics/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
parasitics/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

View File

@ -0,0 +1,6 @@
sta_module_tests("power"
TESTS
report
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestPower TestPower.cc)
target_link_libraries(TestPower
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestPower PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestPower
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_power"
)

1503
power/test/cpp/TestPower.cc Normal file

File diff suppressed because it is too large Load Diff

View File

View File

@ -0,0 +1,27 @@
# Test power reporting
read_liberty ../../test/sky130hd/sky130_fd_sc_hd__tt_025C_1v80.lib
read_verilog power_test1.v
link_design power_test1
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk 0 [get_ports in1]
set_output_delay -clock clk 0 [get_ports out1]
set_input_transition 0.1 [get_ports in1]
set_power_activity -global -activity 0.5 -duty 0.5
# Report power with explicit checks on returned content.
with_output_to_variable pwr_default { report_power }
if {![regexp {Total} $pwr_default]} {
error "report_power output missing Total section"
}
with_output_to_variable pwr_inst { report_power -instances [get_cells reg1] }
if {![regexp {reg1} $pwr_inst]} {
error "instance power report missing reg1 entry"
}
with_output_to_variable pwr_json { report_power -format json }
if {![regexp {"Total"} $pwr_json]} {
error "json power report missing Total field"
}

8
power/test/power_test1.v Normal file
View File

@ -0,0 +1,8 @@
module power_test1 (clk, in1, out1);
input clk, in1;
output out1;
wire n1;
sky130_fd_sc_hd__buf_1 buf1 (.A(in1), .X(n1));
sky130_fd_sc_hd__dfxtp_1 reg1 (.D(n1), .CLK(clk), .Q(out1));
endmodule

1
power/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
power/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

6
sdc/test/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
sta_module_tests("sdc"
TESTS
clocks
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestSdcClasses TestSdcClasses.cc)
target_link_libraries(TestSdcClasses
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestSdcClasses PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestSdcClasses
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_sdc"
)

File diff suppressed because it is too large Load Diff

1
sdc/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
sdc/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

22
sdc/test/sdc_clocks.ok Normal file
View File

@ -0,0 +1,22 @@
Clock Period Waveform
----------------------------------------------------
clk1 10.00 0.00 5.00
clk2 20.00 0.00 10.00
vclk 5.00 0.00 2.50
clk1_fast 5.00 0.00 2.50
Warning 1061: generated clock gen_clk_div2 pin clk1 is in the fanout of multiple clocks.
Clock Period Waveform
----------------------------------------------------
clk1 10.00 0.00 5.00
clk2 20.00 0.00 10.00
vclk 5.00 0.00 2.50
clk1_fast 5.00 0.00 2.50
gen_clk_div2 10.00 0.00 5.00 (generated)
gen_clk_mul3 6.67 0.00 3.33 (generated)
Warning 415: sdc_clocks.tcl line 1, set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock.
No paths found.
Clock Period Waveform
----------------------------------------------------
clk1 10.00 0.00 5.00
clk2 20.00 0.00 10.00
clk1_fast 5.00 0.00 2.50

142
sdc/test/sdc_clocks.tcl Normal file
View File

@ -0,0 +1,142 @@
# Test comprehensive clock SDC commands for code coverage
read_liberty ../../test/nangate45/Nangate45_typ.lib
read_verilog sdc_test2.v
link_design sdc_test2
############################################################
# create_clock with various options
############################################################
# Basic clock
create_clock -name clk1 -period 10 [get_ports clk1]
# Clock with waveform
create_clock -name clk2 -period 20 -waveform {0 10} [get_ports clk2]
# Virtual clock (no port)
create_clock -name vclk -period 5
# Clock with -add on same port (additional clock definition)
create_clock -name clk1_fast -period 5 -add [get_ports clk1]
# Report clock properties
report_clock_properties
############################################################
# create_generated_clock
############################################################
create_generated_clock -name gen_clk_div2 -source [get_ports clk1] -divide_by 2 [get_pins reg1/Q]
create_generated_clock -name gen_clk_mul3 -source [get_ports clk2] -multiply_by 3 [get_pins reg3/Q]
report_clock_properties
############################################################
# set_clock_latency
############################################################
# Source latency with rise/fall min/max
set_clock_latency -source 0.5 [get_clocks clk1]
set_clock_latency -source -rise -max 0.6 [get_clocks clk1]
set_clock_latency -source -fall -min 0.3 [get_clocks clk1]
# Network latency
set_clock_latency 0.2 [get_clocks clk2]
set_clock_latency -rise -max 0.4 [get_clocks clk2]
set_clock_latency -fall -min 0.1 [get_clocks clk2]
############################################################
# set_clock_uncertainty
############################################################
# Simple clock uncertainty
set_clock_uncertainty -setup 0.2 [get_clocks clk1]
set_clock_uncertainty -hold 0.1 [get_clocks clk1]
# Inter-clock uncertainty
set_clock_uncertainty -from [get_clocks clk1] -to [get_clocks clk2] -setup 0.3
set_clock_uncertainty -from [get_clocks clk1] -to [get_clocks clk2] -hold 0.15
############################################################
# set_clock_transition
############################################################
set_clock_transition -rise -max 0.15 [get_clocks clk1]
set_clock_transition -fall -min 0.08 [get_clocks clk1]
set_clock_transition 0.1 [get_clocks clk2]
############################################################
# set_propagated_clock
############################################################
set_propagated_clock [get_clocks clk1]
############################################################
# set_clock_groups
############################################################
set_clock_groups -logically_exclusive -group [get_clocks clk1] -group [get_clocks clk2]
# Remove and re-add as physically exclusive
unset_clock_groups -logically_exclusive -all
set_clock_groups -physically_exclusive -group [get_clocks clk1] -group [get_clocks clk2]
unset_clock_groups -physically_exclusive -all
set_clock_groups -asynchronous -group [get_clocks clk1] -group [get_clocks clk2]
unset_clock_groups -asynchronous -all
############################################################
# set_clock_sense
############################################################
set_clock_sense -positive -clocks [get_clocks clk1] [get_pins buf1/Z]
############################################################
# report_checks to verify constraint effects
############################################################
report_checks -from [get_ports in1] -to [get_ports out1]
############################################################
# Unset/cleanup operations
############################################################
unset_propagated_clock [get_clocks clk1]
unset_clock_latency [get_clocks clk1]
unset_clock_latency [get_clocks clk2]
unset_clock_latency -source [get_clocks clk1]
unset_clock_transition [get_clocks clk1]
unset_clock_uncertainty -setup [get_clocks clk1]
unset_clock_uncertainty -hold [get_clocks clk1]
unset_clock_uncertainty -from [get_clocks clk1] -to [get_clocks clk2] -setup
unset_clock_uncertainty -from [get_clocks clk1] -to [get_clocks clk2] -hold
# Delete generated clocks
delete_generated_clock [get_clocks gen_clk_div2]
delete_generated_clock [get_clocks gen_clk_mul3]
# Delete regular clocks
delete_clock [get_clocks vclk]
report_clock_properties

16
sdc/test/sdc_test2.v Normal file
View File

@ -0,0 +1,16 @@
module sdc_test2 (clk1, clk2, in1, in2, in3, out1, out2);
input clk1, clk2, in1, in2, in3;
output out1, out2;
wire n1, n2, n3, n4, n5, n6, n7;
BUF_X1 buf1 (.A(in1), .Z(n1));
INV_X1 inv1 (.A(in2), .ZN(n2));
AND2_X1 and1 (.A1(n1), .A2(n2), .ZN(n3));
OR2_X1 or1 (.A1(n1), .A2(in3), .ZN(n4));
NAND2_X1 nand1 (.A1(n3), .A2(n4), .ZN(n5));
NOR2_X1 nor1 (.A1(n3), .A2(n4), .ZN(n6));
DFF_X1 reg1 (.D(n5), .CK(clk1), .Q(n7));
DFF_X1 reg2 (.D(n6), .CK(clk1), .Q(out1));
DFF_X1 reg3 (.D(n7), .CK(clk2), .Q(out2));
endmodule

6
sdf/test/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
sta_module_tests("sdf"
TESTS
annotation
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestSdf TestSdf.cc)
target_link_libraries(TestSdf
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestSdf PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestSdf
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_sdf"
)

1699
sdf/test/cpp/TestSdf.cc Normal file

File diff suppressed because it is too large Load Diff

1
sdf/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
sdf/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

255
sdf/test/sdf_annotation.ok Normal file
View File

@ -0,0 +1,255 @@
--- read_sdf ---
--- report_annotated_delay (all) ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
cell arcs 3 2 1
internal net arcs 1 0 1
net arcs from primary inputs 2 0 2
net arcs to primary outputs 1 0 1
----------------------------------------------------------------
7 2 5
--- report_annotated_delay -cell ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
cell arcs 3 2 1
----------------------------------------------------------------
3 2 1
--- report_annotated_delay -net ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
internal net arcs 1 0 1
----------------------------------------------------------------
1 0 1
--- report_annotated_delay -from_in_ports ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
net arcs from primary inputs 2 0 2
----------------------------------------------------------------
2 0 2
--- report_annotated_delay -to_out_ports ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
net arcs to primary outputs 1 0 1
----------------------------------------------------------------
1 0 1
--- report_annotated_delay -cell -report_annotated ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
cell arcs 3 2 1
----------------------------------------------------------------
3 2 1
Annotated Arcs
delay buf1/A -> buf1/Z
delay reg1/CK -> reg1/Q
--- report_annotated_delay -cell -report_unannotated ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
cell arcs 3 2 1
----------------------------------------------------------------
3 2 1
Unannotated Arcs
delay reg1/CK -> reg1/QN
--- report_annotated_delay -constant_arcs ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
cell arcs 3 2 1
constant arcs 0 0
internal net arcs 1 0 1
constant arcs 0 0
net arcs from primary inputs 2 0 2
constant arcs 0 0
net arcs to primary outputs 1 0 1
constant arcs 0 0
----------------------------------------------------------------
7 2 5
--- report_annotated_delay -max_lines 5 ---
Not
Delay type Total Annotated Annotated
----------------------------------------------------------------
cell arcs 3 2 1
internal net arcs 1 0 1
net arcs from primary inputs 2 0 2
net arcs to primary outputs 1 0 1
----------------------------------------------------------------
7 2 5
--- report_annotated_check (all) ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell setup arcs 1 0 1
cell hold arcs 1 0 1
cell width arcs 1 0 1
----------------------------------------------------------------
3 0 3
--- report_annotated_check -setup ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell setup arcs 1 0 1
----------------------------------------------------------------
1 0 1
--- report_annotated_check -hold ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell hold arcs 1 0 1
----------------------------------------------------------------
1 0 1
--- report_annotated_check -recovery ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
----------------------------------------------------------------
0 0 0
--- report_annotated_check -removal ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
----------------------------------------------------------------
0 0 0
--- report_annotated_check -width ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell width arcs 1 0 1
----------------------------------------------------------------
1 0 1
--- report_annotated_check -period ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
----------------------------------------------------------------
0 0 0
--- report_annotated_check -setup -report_annotated ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell setup arcs 1 0 1
----------------------------------------------------------------
1 0 1
Annotated Arcs
--- report_annotated_check -setup -report_unannotated ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell setup arcs 1 0 1
----------------------------------------------------------------
1 0 1
Unannotated Arcs
setup reg1/CK -> reg1/D
--- report_annotated_check -constant_arcs ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell setup arcs 1 0 1
constant arcs 0 0
cell hold arcs 1 0 1
constant arcs 0 0
cell width arcs 1 0 1
constant arcs 0 0
----------------------------------------------------------------
3 0 3
--- report_annotated_check -max_lines 5 ---
Not
Check type Total Annotated Annotated
----------------------------------------------------------------
cell setup arcs 1 0 1
cell hold arcs 1 0 1
cell width arcs 1 0 1
----------------------------------------------------------------
3 0 3
--- report_checks (shows annotated delays) ---
Startpoint: reg1 (rising edge-triggered flip-flop clocked by clk)
Endpoint: q (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ reg1/CK (DFF_X1)
0.40 0.40 ^ reg1/Q (DFF_X1)
0.00 0.40 ^ q (out)
0.40 data arrival time
10.00 10.00 clock clk (rise edge)
0.00 10.00 clock network delay (ideal)
0.00 10.00 clock reconvergence pessimism
0.00 10.00 output external delay
10.00 data required time
---------------------------------------------------------
10.00 data required time
-0.40 data arrival time
---------------------------------------------------------
9.60 slack (MET)
--- report_checks -format full_clock ---
Startpoint: reg1 (rising edge-triggered flip-flop clocked by clk)
Endpoint: q (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ reg1/CK (DFF_X1)
0.40 0.40 ^ reg1/Q (DFF_X1)
0.00 0.40 ^ q (out)
0.40 data arrival time
10.00 10.00 clock clk (rise edge)
0.00 10.00 clock network delay (ideal)
0.00 10.00 clock reconvergence pessimism
0.00 10.00 output external delay
10.00 data required time
---------------------------------------------------------
10.00 data required time
-0.40 data arrival time
---------------------------------------------------------
9.60 slack (MET)
--- report_checks -path_delay min ---
Startpoint: d (input port clocked by clk)
Endpoint: reg1 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: min
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ input external delay
0.00 0.00 ^ d (in)
0.10 0.10 ^ buf1/Z (BUF_X1)
0.00 0.10 ^ reg1/D (DFF_X1)
0.10 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 ^ reg1/CK (DFF_X1)
0.00 0.00 library hold time
0.00 data required time
---------------------------------------------------------
0.00 data required time
-0.10 data arrival time
---------------------------------------------------------
0.10 slack (MET)

View File

@ -0,0 +1,80 @@
# Test SDF annotation and reporting commands
read_liberty ../../test/nangate45/Nangate45_typ.lib
read_verilog sdf_test1.v
link_design sdf_test1
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk 0 [get_ports d]
set_output_delay -clock clk 0 [get_ports q]
puts "--- read_sdf ---"
read_sdf sdf_test1.sdf
puts "--- report_annotated_delay (all) ---"
report_annotated_delay
puts "--- report_annotated_delay -cell ---"
report_annotated_delay -cell
puts "--- report_annotated_delay -net ---"
report_annotated_delay -net
puts "--- report_annotated_delay -from_in_ports ---"
report_annotated_delay -from_in_ports
puts "--- report_annotated_delay -to_out_ports ---"
report_annotated_delay -to_out_ports
puts "--- report_annotated_delay -cell -report_annotated ---"
report_annotated_delay -cell -report_annotated
puts "--- report_annotated_delay -cell -report_unannotated ---"
report_annotated_delay -cell -report_unannotated
puts "--- report_annotated_delay -constant_arcs ---"
report_annotated_delay -constant_arcs
puts "--- report_annotated_delay -max_lines 5 ---"
report_annotated_delay -max_lines 5
puts "--- report_annotated_check (all) ---"
report_annotated_check
puts "--- report_annotated_check -setup ---"
report_annotated_check -setup
puts "--- report_annotated_check -hold ---"
report_annotated_check -hold
puts "--- report_annotated_check -recovery ---"
report_annotated_check -recovery
puts "--- report_annotated_check -removal ---"
report_annotated_check -removal
puts "--- report_annotated_check -width ---"
report_annotated_check -width
puts "--- report_annotated_check -period ---"
report_annotated_check -period
puts "--- report_annotated_check -setup -report_annotated ---"
report_annotated_check -setup -report_annotated
puts "--- report_annotated_check -setup -report_unannotated ---"
report_annotated_check -setup -report_unannotated
puts "--- report_annotated_check -constant_arcs ---"
report_annotated_check -constant_arcs
puts "--- report_annotated_check -max_lines 5 ---"
report_annotated_check -max_lines 5
puts "--- report_checks (shows annotated delays) ---"
report_checks
puts "--- report_checks -format full_clock ---"
report_checks -format full_clock
puts "--- report_checks -path_delay min ---"
report_checks -path_delay min

23
sdf/test/sdf_test1.sdf Normal file
View File

@ -0,0 +1,23 @@
(DELAYFILE
(SDFVERSION "3.0")
(DESIGN "sdf_test1")
(TIMESCALE 1ns)
(CELL
(CELLTYPE "BUF_X1")
(INSTANCE buf1)
(DELAY
(ABSOLUTE
(IOPATH A Z (0.1:0.2:0.3) (0.1:0.2:0.3))
)
)
)
(CELL
(CELLTYPE "DFF_X1")
(INSTANCE reg1)
(DELAY
(ABSOLUTE
(IOPATH CK Q (0.2:0.3:0.4) (0.2:0.3:0.4))
)
)
)
)

8
sdf/test/sdf_test1.v Normal file
View File

@ -0,0 +1,8 @@
module sdf_test1 (clk, d, q);
input clk, d;
output q;
wire n1;
BUF_X1 buf1 (.A(d), .Z(n1));
DFF_X1 reg1 (.D(n1), .CK(clk), .Q(q));
endmodule

View File

@ -0,0 +1,6 @@
sta_module_tests("search"
TESTS
timing
)
add_subdirectory(cpp)

View File

@ -0,0 +1,16 @@
add_executable(TestSearchClasses TestSearchClasses.cc)
target_link_libraries(TestSearchClasses
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestSearchClasses PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestSearchClasses
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_search"
)

File diff suppressed because it is too large Load Diff

1
search/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
search/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

View File

@ -0,0 +1,10 @@
module search_test1 (clk, in1, in2, out1);
input clk, in1, in2;
output out1;
wire n1, n2, n3;
AND2_X1 and1 (.A1(in1), .A2(in2), .ZN(n1));
BUF_X1 buf1 (.A(n1), .Z(n2));
DFF_X1 reg1 (.D(n2), .CK(clk), .Q(n3));
BUF_X1 buf2 (.A(n3), .Z(out1));
endmodule

View File

@ -0,0 +1,57 @@
Startpoint: reg1 (rising edge-triggered flip-flop clocked by clk)
Endpoint: out1 (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ reg1/CK (DFF_X1)
0.08 0.08 ^ reg1/Q (DFF_X1)
0.02 0.10 ^ buf2/Z (BUF_X1)
0.00 0.10 ^ out1 (out)
0.10 data arrival time
10.00 10.00 clock clk (rise edge)
0.00 10.00 clock network delay (ideal)
0.00 10.00 clock reconvergence pessimism
-2.00 8.00 output external delay
8.00 data required time
---------------------------------------------------------
8.00 data required time
-0.10 data arrival time
---------------------------------------------------------
7.90 slack (MET)
Startpoint: in1 (input port clocked by clk)
Endpoint: reg1 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: min
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
1.00 1.00 ^ input external delay
0.00 1.00 ^ in1 (in)
0.02 1.02 ^ and1/ZN (AND2_X1)
0.02 1.04 ^ buf1/Z (BUF_X1)
0.00 1.04 ^ reg1/D (DFF_X1)
1.04 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 ^ reg1/CK (DFF_X1)
0.00 0.00 library hold time
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.04 data arrival time
---------------------------------------------------------
1.04 slack (MET)
Worst slack: 7.899713772019368e-9

View File

@ -0,0 +1,23 @@
# Full timing analysis flow test
read_liberty ../../test/nangate45/Nangate45_typ.lib
read_verilog search_test1.v
link_design search_test1
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk 1.0 [get_ports in1]
set_input_delay -clock clk 1.0 [get_ports in2]
set_output_delay -clock clk 2.0 [get_ports out1]
# Setup analysis
report_checks -path_delay max
# Hold analysis
report_checks -path_delay min
# Check worst slack
set slack [sta::worst_slack_cmd "max"]
puts "Worst slack: $slack"
if { $slack == "" } {
puts "FAIL: no slack found"
exit 1
}

View File

@ -0,0 +1,6 @@
sta_module_tests("spice"
TESTS
write
)
add_subdirectory(cpp)

View File

@ -0,0 +1,17 @@
add_executable(TestSpice TestSpice.cc)
target_link_libraries(TestSpice
OpenSTA
GTest::gtest
GTest::gtest_main
${TCL_LIBRARY}
)
target_include_directories(TestSpice PRIVATE
${STA_HOME}/include/sta
${STA_HOME}
${STA_HOME}/spice
${CMAKE_BINARY_DIR}/include/sta
)
gtest_discover_tests(TestSpice
WORKING_DIRECTORY ${STA_HOME}
PROPERTIES LABELS "cpp\;module_spice"
)

1866
spice/test/cpp/TestSpice.cc Normal file

File diff suppressed because it is too large Load Diff

1
spice/test/regression Symbolic link
View File

@ -0,0 +1 @@
../../test/regression

1
spice/test/save_ok Symbolic link
View File

@ -0,0 +1 @@
../../test/shared/save_ok

8
spice/test/spice_test1.v Normal file
View File

@ -0,0 +1,8 @@
module spice_test1 (clk, in1, out1);
input clk, in1;
output out1;
wire n1;
BUF_X1 buf1 (.A(in1), .Z(n1));
DFF_X1 reg1 (.D(n1), .CK(clk), .Q(out1));
endmodule

29
spice/test/spice_write.ok Normal file
View File

@ -0,0 +1,29 @@
Startpoint: reg1 (rising edge-triggered flip-flop clocked by clk)
Endpoint: out1 (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ reg1/CK (DFF_X1)
0.08 0.08 ^ reg1/Q (DFF_X1)
0.00 0.08 ^ out1 (out)
0.08 data arrival time
10.00 10.00 clock clk (rise edge)
0.00 10.00 clock network delay (ideal)
0.00 10.00 clock reconvergence pessimism
0.00 10.00 output external delay
10.00 data required time
---------------------------------------------------------
10.00 data required time
-0.08 data arrival time
---------------------------------------------------------
9.92 slack (MET)
Differences found at line 2.
.include "/workspace/sta/OpenSTA/spice/test/results/spice_out/mock_model.sp"
.include "/workspace/sta2/OpenSTA/spice/test/results/spice_out/mock_model.sp"

View File

@ -0,0 +1,59 @@
* Path from reg1/Q ^ to out1 ^
.include "/workspace/sta/OpenSTA/spice/test/results/spice_out/mock_model.sp"
.include "path_1.subckt"
.tran 1e-13 3.1e-08
.print tran v(clk) v(reg1/CK) v(reg1/Q) v(out1)
**************
* Input source
**************
v1 clk 0 pwl(
+0.000e+00 0.000e+00
+9.985e-10 0.000e+00
+1.001e-09 1.100e+00
+5.999e-09 1.100e+00
+6.001e-09 0.000e+00
+1.100e-08 0.000e+00
+1.100e-08 1.100e+00
+1.600e-08 1.100e+00
+1.600e-08 0.000e+00
+2.100e-08 0.000e+00
+2.100e-08 1.100e+00
+2.600e-08 1.100e+00
+2.600e-08 0.000e+00
+3.100e-08 0.000e+00
+)
*****************
* Stage instances
*****************
xstage1 clk reg1/CK stage1
xstage2 reg1/CK reg1/Q out1 stage2
***************
* Stage subckts
***************
.subckt stage1 clk reg1/CK
* Net clk
* Net has no parasitics.
R1 clk reg1/CK 1.000e-04
.ends
.subckt stage2 reg1/CK reg1/Q out1
* Gate reg1 CK -> Q
xreg1 reg1/D reg1/CK reg1/Q reg1/VDD reg1/VSS DFF_X1
v1 reg1/D 0 1.100
v2 reg1/VDD 0 1.100
v3 reg1/VSS 0 0.000
* Load pins
* Net out1
* Net has no parasitics.
R1 reg1/Q out1 1.000e-04
.ends
.end

View File

@ -0,0 +1,50 @@
# Test spice-related functionality
source ../../test/helpers.tcl
set test_name spice_write
read_liberty ../../test/nangate45/Nangate45_typ.lib
read_verilog spice_test1.v
link_design spice_test1
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk 0 [get_ports in1]
set_output_delay -clock clk 0 [get_ports out1]
# Run timing analysis (needed before write_path_spice)
report_checks
# Create mock SPICE model and subckt files for write_path_spice
set spice_dir [make_result_file spice_out]
file mkdir $spice_dir
set model_file [file join $spice_dir mock_model.sp]
set model_fh [open $model_file w]
puts $model_fh "* Mock SPICE model file"
puts $model_fh ".model nmos nmos level=1"
puts $model_fh ".model pmos pmos level=1"
close $model_fh
set subckt_file [file join $spice_dir mock_subckt.sp]
set subckt_fh [open $subckt_file w]
puts $subckt_fh "* Mock SPICE subckt file"
puts $subckt_fh ".subckt BUF_X1 A Z VDD VSS"
puts $subckt_fh "M1 Z A VDD VDD pmos W=1u L=100n"
puts $subckt_fh "M2 Z A VSS VSS nmos W=1u L=100n"
puts $subckt_fh ".ends"
puts $subckt_fh ""
puts $subckt_fh ".subckt DFF_X1 D CK Q VDD VSS"
puts $subckt_fh "M1 Q D VDD VDD pmos W=1u L=100n"
puts $subckt_fh "M2 Q D VSS VSS nmos W=1u L=100n"
puts $subckt_fh ".ends"
close $subckt_fh
# write_path_spice - exercises the Tcl command parsing and
# C++ WritePathSpice code paths.
write_path_spice \
-path_args {-sort_by_slack} \
-spice_directory $spice_dir \
-lib_subckt_file $subckt_file \
-model_file $model_file \
-power VDD \
-ground VSS
diff_files $test_name.spok [file join $spice_dir path_1.sp]

38
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,38 @@
# Register existing upstream Tcl tests for ctest coverage
set(STA_EXE $<TARGET_FILE:sta>)
set(TEST_DIR ${STA_HOME}/test)
set(EXAMPLES_DIR ${STA_HOME}/examples)
function(sta_tcl_test test_name)
add_test(
NAME tcl.${test_name}
COMMAND ${STA_EXE} -no_init -no_splash -exit ${TEST_DIR}/${test_name}.tcl
WORKING_DIRECTORY ${TEST_DIR}
)
set_tests_properties(tcl.${test_name} PROPERTIES LABELS "tcl")
endfunction()
function(sta_example_test test_name)
add_test(
NAME tcl.example.${test_name}
COMMAND ${STA_EXE} -no_init -no_splash -exit ${EXAMPLES_DIR}/${test_name}.tcl
WORKING_DIRECTORY ${EXAMPLES_DIR}
)
set_tests_properties(tcl.example.${test_name} PROPERTIES LABELS "tcl;example")
endfunction()
# Auto-detect public tests: register all *.ok files that have a matching *.tcl
file(GLOB ok_files "${TEST_DIR}/*.ok")
foreach(ok_file ${ok_files})
get_filename_component(test_name ${ok_file} NAME_WE)
if(EXISTS "${TEST_DIR}/${test_name}.tcl")
sta_tcl_test(${test_name})
endif()
endforeach()
# Auto-detect example tests: register all *.tcl files in examples/
file(GLOB example_tcl_files "${EXAMPLES_DIR}/*.tcl")
foreach(tcl_file ${example_tcl_files})
get_filename_component(test_name ${tcl_file} NAME_WE)
sta_example_test(${test_name})
endforeach()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More