Docs / SCOAP API

This page gives a quick developer reference for the SCOAP API surface in OpenTestability.

Purpose

SCOAP computes structural testability metrics:

These metrics are used directly in DFT analysis and test-point selection workflows.

Primary package

Common imports

from opentestability.core.scoap import run
from opentestability.core.scoap.accelerated import build_scoap_accelerated

Main entry point

run(input_filename, output_filename, json_flag=False, reconvergence_data=None, reconvergent_roots=None)

Runs SCOAP end to end. Internally delegates to build_scoap_accelerated().

Key arguments:

Argument Meaning
input_filename parsed netlist input
output_filename output report/metrics file
json_flag output JSON when True
reconvergence_data optional reconvergence metadata
reconvergent_roots fanout roots for reconvergence-aware processing

Accelerated engine

The runtime uses Cython-compiled kernels (core/scoap/_kernels.pyx) via build_scoap_accelerated(). The pure-Python build_controllability_sequential and build_observability functions are kept as reference oracles for testing only; they are not the runtime path.

from opentestability.core.scoap.accelerated import build_scoap_accelerated

ctrl, obs = build_scoap_accelerated(nets, inputs, outputs, gates, method="topo")
# ctrl: {"CC0_<sig>": int, "CC1_<sig>": int, ...}
# obs:  {"CO_<sig>": int, ...}
# math.inf marks a signal that is uncontrollable (CC0/CC1) or unobservable (CO),
# e.g. a primary input with no fan-out into the combinational core after the
# full-scan cut. It is a real, unbounded metric, not a "not computed" marker.

Kernel methods (all produce identical results: the same least fixpoint):

Method Description When to use
"topo" (default) controllability in one topological pass; observability as reverse-topo fixpoint always (fewest iterations)
"fixpoint" gate-index-order fixpoint loop equivalence testing against reference
"parallel" Cython OpenMP prange chaotic relaxation SoC-scale circuits on multi-core hosts

Minimal examples

Basic run:

from opentestability.core.scoap import run

run(
    input_filename="circuit.txt",
    output_filename="scoap_results.json",
    json_flag=True,
)

Direct accelerated-engine call:

from opentestability.core.scoap.accelerated import build_scoap_accelerated

ctrl, obs = build_scoap_accelerated(nets, inputs, outputs, gates)
print(ctrl["CC0_N22"], ctrl["CC1_N22"])  # c17: (5, 4)

JSON output (json_flag=True)

run(..., json_flag=True) writes a metrics array (one entry per primary input and per gate) next to the requested output file. Each cc0, cc1, and co field is encoded as follows (JSON has no native infinity):

Value Meaning
a number the computed SCOAP cost
"inf" (string) infinite metric: uncontrollable (cc0/cc1) or unobservable (co). A real, unbounded value; parse it back with float("inf")
null metric genuinely absent from the result, a gap that should not occur; distinct from "inf" so it is not silently read as “unobservable”

For a sequential design such as s27, the constants and the clock/reset control inputs drive nothing after the full-scan cut, so their co is "inf". (Earlier versions emitted null for these, conflating “unobservable” with “not computed”.)

Notes for developers

  1. COP API
  2. Algorithms
  3. Reconvergence Integration