Core Module API

The core module contains the main analysis engines for testability metrics and reconvergence detection. The module is organized into focused sub-packages:

Module: scoap Package

SCOAP (Sandia Controllability/Observability Analysis Program) implementation with modular architecture.

Main Entry Point

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

Main entry point for SCOAP analysis with parallel computation support.

Parameters:

Returns:

Example:

from opentestability.core.scoap import run

# Sequential mode (default)
run("circuit.txt", "scoap_results.txt", json_flag=False)

# Parallel mode with reconvergent roots
run("circuit.txt", "scoap_parallel.txt",
    reconvergent_roots=['n5', 'n12'],
    parallel=True,
    max_workers=4,
    json_flag=True)

Import Paths:

# Recommended imports
from opentestability.core.scoap import run
from opentestability.core.scoap import build_controllability, build_observability

# Backward compatible (still supported)
from opentestability.core import run_scoap

SCOAP Sub-modules

The SCOAP package is split into focused modules:

scoap/main.py

scoap/netlist_parser.py

scoap/gate_logic.py

scoap/controllability.py

scoap/observability.py

scoap/parallel.py

scoap/output.py

Parallel Computation:

When parallel=True and reconvergent_roots is provided, the algorithm:

  1. Identifies reconvergent cones for each fanout point
  2. Computes sequential (non-reconvergent) gates first
  3. Spawns parallel threads for each reconvergent cone
  4. Waits for all parallel computations to complete (synchronization barrier)
  5. Performs final convergence pass

See Core Reorganization Documentation for details about the modular architecture.

calculate_scoap(gates, inputs, outputs)

Calculate SCOAP metrics for all signals in the circuit.

Parameters:

Returns:

Metrics:

Example:

gates = [
    {"type": "AND2X1", "output": "n1", "inputs": ["a", "b"]},
    {"type": "INVX1", "output": "z", "inputs": ["n1"]}
]
inputs = ["a", "b"]
outputs = ["z"]

metrics = calculate_scoap(gates, inputs, outputs)
# metrics = {
#   "a": {"CC0": 1, "CC1": 1, "CO": 2},
#   "b": {"CC0": 1, "CC1": 1, "CO": 2},
#   "n1": {"CC0": 2, "CC1": 2, "CO": 1},
#   "z": {"CC0": 3, "CC1": 3, "CO": 0}
# }

Gate Type Support

Supported gate types:


Module: dag Package

DAG (Directed Acyclic Graph) construction from parsed netlists.

Main Functions

create_dag_from_netlist(json_filename, compute_reconvergence=False, reconv_algorithm='simple')

Create a complete DAG from a parsed netlist JSON file with optional reconvergence analysis.

Parameters:

Returns:

Raises:

Example:

from opentestability.core.dag import create_dag_from_netlist

# Basic DAG without reconvergence
dag_path = create_dag_from_netlist("circuit_parsed.json")

# DAG with reconvergence analysis
dag_path = create_dag_from_netlist("circuit_parsed.json",
                                   compute_reconvergence=True,
                                   reconv_algorithm='simple')
# Creates: data/dag_output/circuit_parsed_dag.json

Import Paths:

# Recommended
from opentestability.core.dag import create_dag_from_netlist

# Backward compatible (still supported)
from opentestability.core.dag_builder import create_dag_from_netlist
from opentestability.core import dag_builder

build_dag(gates)

Build DAG edges and labels from gate list.

Parameters:

Returns:

Example:

from opentestability.core.dag import build_dag

gates = [
    {"type": "AND2X1", "output": "n1", "inputs": ["a", "b"]},
    {"type": "OR2X1", "output": "z", "inputs": ["n1", "c"]}
]

edges, labels = build_dag(gates)
# edges = [["a", "n1"], ["b", "n1"], ["n1", "z"], ["c", "z"]]
# labels = {
#   "a": "a",
#   "b": "b", 
#   "c": "c",
#   "n1": "n1 (AND2X1)",
#   "z": "z (OR2X1)"
# }

load_parsed_netlist(json_filename)

Load a parsed netlist JSON file.

Parameters:

Returns:

Raises:

flatten_signal(signal)

Flatten vector signals like A[7:0] into individual bit signals.

Parameters:

Returns:

Example:

from opentestability.core.dag_builder import flatten_signal

flatten_signal("data[3:0]")
# Returns: ["data[3]", "data[2]", "data[1]", "data[0]"]

flatten_signal("clk")
# Returns: ["clk"]

save_dag_json(dag_data, input_filename)

Save DAG data to JSON file.

Parameters:

Returns:


Module: reconvergence Package

Multiple algorithms for reconvergent fanout detection. The package contains three implementations:

Choosing an Algorithm

Algorithm Accuracy Performance Use Case
Simple (Recommended) 98%+ Fast Production applications
Basic Standard Very Fast Baseline comparison
Advanced Research-grade Moderate Complex pipelined circuits

Basic Algorithm (reconvergence.basic)

find_reconvergences(dag_data, print_progress=False)

Basic reconvergent fanout detection.

Functions

analyze_reconvergence(dag_filename)

Analyze reconvergent fanout in a DAG.

Parameters:

Returns:

Example:

from opentestability.core.reconvergence import analyze_reconvergence

result_path = analyze_reconvergence("circuit_dag.json")
# Creates: data/reconvergence_output/circuit_dag_reconv.json

Algorithm

Detects points where:

  1. A signal fans out to multiple paths
  2. Those paths reconverge at a common gate

Output Format:

[
  {
    "fanout_point": "n5",
    "reconverge_point": "n12",
    "paths": [
      ["n5", "n7", "n10", "n12"],
      ["n5", "n8", "n11", "n12"]
    ]
  }
]

Module: simple_reconvergence.py

Enhanced reconvergence detection with additional metrics.

Functions

analyze_with_simple_reconvergence(dag_filename)

Run simple reconvergence analysis.

Parameters:

Returns:

Example:

from opentestability.core.simple_reconvergence import analyze_with_simple_reconvergence

analyze_with_simple_reconvergence("circuit_dag.json")

Additional Metrics:


Module: advanced_reconvergence.py

Advanced reconvergence analysis with comprehensive path enumeration.

Functions

analyze_with_advanced_reconvergence(dag_filename)

Run advanced reconvergence analysis.

Parameters:

Returns:

Example:

from opentestability.core.advanced_reconvergence import analyze_with_advanced_reconvergence

analyze_with_advanced_reconvergence("circuit_dag.json")

Features:


Sequential Circuit Handling

All core modules handle sequential circuits by:

  1. Flip-flops as Boundaries: Storage elements (DFF, LATCH) break feedback loops
  2. Pseudo-Primary I/O:
    • Flip-flop Q outputs → treated as primary inputs
    • Flip-flop D inputs → treated as primary outputs
  3. Clock Handling: Clock signals are preserved but not analyzed in data paths

Example: Sequential Circuit

// Has feedback through flip-flops
DFFRX1 reg1(.D(n5), .CK(clk), .Q(state));  // Storage element
AND2X1 gate1(.A(state), .B(input), .Y(n5));  // Combinational logic

DAG Representation:

This is the industry-standard approach used in:

Integration Example

Complete workflow using core APIs:

from opentestability.parsers.verilog_parser import parse
from opentestability.core.dag_builder import create_dag_from_netlist
from opentestability.core.scoap import run as scoap_run
from opentestability.core.reconvergence import analyze_reconvergence
from opentestability.visualization.graph_renderer import visualize_gate_graph

# Step 1: Parse Verilog
parse("circuit.v", "circuit.txt")

# Step 2: Create DAG
dag_path = create_dag_from_netlist("circuit_parsed.json")

# Step 3: SCOAP Analysis
scoap_run("circuit.txt", "scoap.json", json_flag=True)

# Step 4: Reconvergence
reconv_path = analyze_reconvergence("circuit_dag.json")

# Step 5: Visualize
visualize_gate_graph("circuit_dag.json")

print("Analysis complete!")