OpenTestability combines metric engines (COP/SCOAP) with reconvergence detection.
Metric engines
| Engine | Outputs | Typical use |
|---|---|---|
| COP | probabilistic controllability and observability | ranking signals for probability-aware test planning |
| SCOAP | CC0, CC1, CO structural testability metrics | fast baseline analysis and traditional DFT scoring |
Core formulas
COP uses probability transfer through gates. Example for two-input AND:
\[P(out=1)=P(a=1)\times P(b=1)\]SCOAP uses integer transfer. Example for two-input AND:
\[CC0(out)=\min(CC0(a),CC0(b))+1\] \[CC1(out)=CC1(a)+CC1(b)+1\]Reconvergence options
| Algorithm | Complexity | Recommended use |
|---|---|---|
dominator |
polynomial detection, budgeted correction | default, auto-selected; the only detector the COP cofactor (C1) correction consumes |
basic |
O(n^2) |
structural checks only, not auto-selected |
simple |
O(n^2 log n) |
structural checks only, not auto-selected |
advanced |
O(n^2) |
structural checks only, not auto-selected |
dominator detects every reconvergent (stem, site) pair with no cap. Materializing the disjoint paths needed for COP cofactor correction is bounded by a path_budget_seconds parameter (default 30s, Python API) so a densely-reconvergent design corrects the tightest/highest-priority sites first instead of hanging. See Reconvergence Integration for details.
Selection guideline
- Use the default (
dominator) for almost all runs; it’s auto-selected, so no flag is needed. basic/simple/advancedremain available for structural-only checks but are never auto-selected and are not consumed by the COP cofactor (C1) correction. The Obs-side corrections (SCOAP’s reconvergence-depth adjustment, COP’s Bayesian/correlated-observability adjustment) are format-agnostic and do consume records from all four detectors.
Test-point selection algorithms
Which signals become test points is a pluggable choice: pick one with
--tpi-algorithm <name> (--list-algorithms shows what is registered).
Third-party packages can register their own under the
opentestability.tpi_algorithms entry-point group and it becomes selectable by
name with no change to OpenTestability.
| Algorithm | id | Idea |
|---|---|---|
| Difficulty heuristic (default) | heuristic |
Ranks every signal by normalized SCOAP/COP difficulty (percentile), boosts reconvergent fanout signals, and takes the hardest N. |
| Cone-overlap greedy | greedy_cone |
Models each test point by the hard signals its logic cone covers (observation → fan-in cone, control → fan-out cone) and greedily maximizes that coverage (CELF lazy-greedy). De-duplicates signals stacked down one cone: it places one point near the cone tip instead of one per signal. Falls back to the heuristic on a combinational cycle or a very large candidate pool. |
| COP gradient | gradient |
Ranks a signal by the whole-circuit sensitivity of a global COP cost function to improving just that signal’s controllability/observability (Seiss-Trouborst-Schulz, ETC 1991), rather than the signal’s own difficulty or its cone coverage. COP-only; falls back to the heuristic on SCOAP-only metrics or a combinational cycle. |
opentest analyze_and_add_tp -i design.json --scoap --tpi-algorithm greedy_cone
opentest analyze_and_add_tp -i design.json --cop --tpi-algorithm gradient
Engine acceleration
Both metric engines use compiled acceleration backends rather than pure-Python fixpoint loops:
| Engine | Runtime backend | Technique |
|---|---|---|
| COP | core/cop/vectorized.py |
NumPy array ops; precomputed side-input products; single Jacobi sweep per iteration |
| SCOAP | core/scoap/_kernels.pyx (Cython) |
Integer int64 arrays; nogil inner loop; optional OpenMP prange for SoC scale |
The pure-Python reference implementations (controllability.py, observability.py) are retained as test oracles for correctness verification; they are not the runtime path.
Performance on picorv32a (~14 k gates):
- COP observability: 160 s (pure Python) → ~3 s (NumPy vectorized)
- SCOAP full analysis: ~130 s (pure Python) → ~0.15 s (Cython kernel)
Gate classification (core/common/gate_types.GateCode) is computed once per gate during index construction and shared across both engines, eliminating per-iteration string matching. XOR and XNOR are classified correctly (the historical substring bug that caused both to misclassify as OR/NOR has been fixed). The classifier also decides which cells the full-scan model cuts: for the four --tech libraries a cell is a flip-flop or latch when its Liberty cell has an ff or latch group (integrated clock gates count as latches), which covers cells whose names give no hint, such as IHP’s sg13g2_dlhq_1 or Nangate’s TLAT_X1; other cells are recognized by name ($_DFF_*, DFF, LATCH, …).