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 — 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