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:
scoap/: SCOAP testability analysis with parallel computation supportdag/: DAG construction and manipulationreconvergence/: Multiple reconvergent fanout detection algorithms
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:
input_filename(str): Name of parsed netlist file indata/parsed/output_filename(str): Name of output file indata/results/json_flag(bool): If True, output JSON format; if False, output text formatreconvergence_data(dict, optional): Reconvergence analysis data for observability adjustmentsreconvergent_roots(list, optional): List of fanout point signal names for parallel computationparallel(bool): Enable parallel computation for reconvergent cones (default: False)max_workers(int): Maximum number of parallel worker threads (default: 4)
Returns:
str: Path to the generated output file
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
- Main
run()function - entry point for SCOAP analysis
scoap/netlist_parser.py
read_netlist()- Read and parse netlist filesparse_sections()- Parse INPUT, OUTPUT, GATE sectionsexpand_vector()- Expand vectored signals (e.g.,in[7:0])extract_wires()- Extract all wire signals from gates
scoap/gate_logic.py
compute_gate_controllability()- Compute CC0/CC1 for a single gateget_gate_inputs_ready()- Check if gate inputs are ready for computation
scoap/controllability.py
build_controllability_sequential()- Sequential CC0/CC1 computationcompute_sequential_gates()- Compute for non-reconvergent gates
scoap/observability.py
build_observability()- Compute CO valuesadjust_observability_for_reconvergence()- Apply reconvergence adjustments
scoap/parallel.py
identify_reconvergent_cones()- Identify independent reconvergent regionscompute_reconvergent_cone_controllability()- Parallel cone computationbuild_controllability()- Main controllability with parallel support
scoap/output.py
write_scoap()- Write text format resultsdump_json()- Write JSON format results
Parallel Computation:
When parallel=True and reconvergent_roots is provided, the algorithm:
- Identifies reconvergent cones for each fanout point
- Computes sequential (non-reconvergent) gates first
- Spawns parallel threads for each reconvergent cone
- Waits for all parallel computations to complete (synchronization barrier)
- 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:
gates(list): List of gate dictionariesinputs(list): List of primary input signal namesoutputs(list): List of primary output signal names
Returns:
dict: Dictionary mapping signal names to{CC0, CC1, CO}metrics
Metrics:
CC0: Combinational Controllability to 0 (lower = easier)CC1: Combinational Controllability to 1 (lower = easier)CO: Combinational Observability (lower = easier)
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:
- Basic:
AND,NAND,OR,NOR,XOR,XNOR,INV,BUF - Standard Cells:
AND2X1,NAND2X1,OR2X1,NOR2X1, etc. - Multi-input:
AND3X1,NAND4X1, etc. - AOI/OAI:
AOI21X1,OAI22X1, etc. - Flip-flops:
DFFRX1,DFFSX1, etc. (outputs treated as pseudo-inputs)
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:
json_filename(str): Name of JSON file indata/parsed/compute_reconvergence(bool): If True, compute reconvergence data (default: False)reconv_algorithm(str): Algorithm to use - ‘simple’, ‘basic’, or ‘advanced’ (default: ‘simple’)
Returns:
str: Path to the generated DAG JSON file indata/dag_output/
Raises:
FileNotFoundError: If input file doesn’t existValueError: If ‘gates’ key not found in netlist or invalid algorithm name
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:
gates(list): List of gate dictionaries withtype,output,inputs
Returns:
tuple:(edges, labels)where:edges: List of[source, target]pairslabels: Dictionary mapping nodes to their labels
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:
json_filename(str): Name of JSON file indata/parsed/
Returns:
dict: Parsed netlist data with keysgates,primary_inputs,primary_outputs
Raises:
FileNotFoundError: If file doesn’t exist
flatten_signal(signal)
Flatten vector signals like A[7:0] into individual bit signals.
Parameters:
signal(str): Signal name, possibly with vector notation
Returns:
list: List of individual signal names
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:
dag_data(dict): Dictionary withedges,labels,primary_inputs,primary_outputsinput_filename(str): Original input filename (for naming output)
Returns:
str: Path to saved DAG JSON file
Module: reconvergence Package
Multiple algorithms for reconvergent fanout detection. The package contains three implementations:
basic.py: Traditional BFS-based reconvergence detectionsimple.py: Simplified paper algorithm (Xu & Edirisuriya 2004) - Recommendedadvanced.py: Complete paper algorithm with FOBL tracking
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:
dag_filename(str): Name of DAG JSON file indata/dag_output/
Returns:
str: Path to the generated reconvergence results file
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:
- A signal fans out to multiple paths
- 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:
dag_filename(str): Name of DAG JSON file
Returns:
str: Path to results file
Example:
from opentestability.core.simple_reconvergence import analyze_with_simple_reconvergence
analyze_with_simple_reconvergence("circuit_dag.json")
Additional Metrics:
- Path depths
- Fanout degree
- Reconvergence distance
Module: advanced_reconvergence.py
Advanced reconvergence analysis with comprehensive path enumeration.
Functions
analyze_with_advanced_reconvergence(dag_filename)
Run advanced reconvergence analysis.
Parameters:
dag_filename(str): Name of DAG JSON file
Returns:
str: Path to results file
Example:
from opentestability.core.advanced_reconvergence import analyze_with_advanced_reconvergence
analyze_with_advanced_reconvergence("circuit_dag.json")
Features:
- Multi-level reconvergence
- Complete path enumeration
- Structural complexity metrics
- Detailed statistics
Sequential Circuit Handling
All core modules handle sequential circuits by:
- Flip-flops as Boundaries: Storage elements (DFF, LATCH) break feedback loops
- Pseudo-Primary I/O:
- Flip-flop Q outputs → treated as primary inputs
- Flip-flop D inputs → treated as primary outputs
- 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:
state→n5(Q output feeds combinational logic)n5→ flip-flop input (breaks the cycle)- Result: Acyclic graph suitable for analysis
This is the industry-standard approach used in:
- ATPG (Automatic Test Pattern Generation)
- Scan chain insertion
- Timing analysis
- Testability analysis
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!")