Papers
Topics
Authors
Recent
2000 character limit reached

AssertMiner: Module-Level Assertions

Updated 20 November 2025
  • AssertMiner is a framework that generates module-level assertions for RTL designs by combining static AST analysis with LLM-guided inference.
  • It systematically extracts module call graphs, I/O tables, and dataflow graphs to produce precise and semantically rich prompts for assertion synthesis.
  • The approach improves early fault detection and enhances verification coverage, complementing traditional top-level assertion methods.

AssertMiner is a module-level assertion generation framework for Register-Transfer Level (RTL) designs that combines static structural analysis based on Abstract Syntax Trees (ASTs) with LLM-guided inference to synthesize SystemVerilog Assertions (SVAs). Unlike previous approaches that focus primarily on top-level assertions derived from design specifications, AssertMiner targets micro-architectural modules, where design errors are most frequent and difficult to localize. By systematically extracting and leveraging internal module context (module call graphs, I/O tables, and dataflow graphs), AssertMiner prompts LLMs with concise and semantically rich summaries to generate both specifications and deep module-level assertions, thereby increasing the coverage and efficacy of assertion-based verification (ABV) (Lyu et al., 13 Nov 2025).

1. Motivation and Conceptual Framework

Assertion-based verification in RTL design often relies on debugging functional anomalies using top-level assertions. However, errors at the module or submodule level tend to manifest late and lack precise localization. For example, a bug injected in a SHA3 "padder" submodule triggers only delayed or nonspecific alarms when guarded solely by top-level checks, extending debugging time and complicating root cause analysis. AssertMiner addresses this by generating deep, module-local assertions that fire earlier and pinpoint the faulty signal directly.

AssertMiner's central methodological distinction is the decoupling of module specification inference from potentially flawed RTL implementations. By constructing a static, language-agnostic structural representation of the design using ASTs, the framework provides LLMs with focused, implementation-independent prompts. These prompts facilitate the generation of precise, high-utility assertions that are resilient to both spec omissions and RTL-level bugs.

2. Static Structural Extraction

AssertMiner's initial phase conducts a comprehensive, design-wide static analysis to construct three foundational representations:

  • Module Call Graph (GcallG_{call}):

The directed graph Gcall=(V,E)G_{call} = (V, E) has nodes V={m1,…,mn}V = \{m_1, \ldots, m_n\} representing modules, with edges (mi→mj)∈E(m_i \to m_j) \in E indicating that module mim_i instantiates mjm_j.

  • I/O Table per Module:

For every module mm, AssertMiner extracts IO(m)={(p,dir,conn)}IO(m) = \{(p, dir, conn)\}, where pp is a port, dirdir designates direction (input or output), and connconn is the corresponding signal at the parent level.

  • Dataflow Graph (GdataG_{data}):

For each module, Gdata=(N,D)G_{data} = (N, D) consists of signal identifiers NN and directed edges DD capturing intra-module assignments and dependencies (e.g., s1→s2s_1 \to s_2 if s1s_1 influences s2s_2).

A recursive AST traversal algorithm records module declarations, port connectivity, instantiations, and data dependencies, and prunes internal-only signals to yield minimal "signal chains" connecting module inputs to outputs. The key steps are illustrated in the following pseudocode excerpt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function build_structures(AST_root):
  for each module_node in AST_root:
    V.add(module_node.name)
    IO[module_node.name] = parse_ports(module_node.ports)
    for each inst in module_node.instantations:
      E.add((module_node.name, inst.module_name))
      resolve_connections(IO, module_node.name, inst)
    for each stmt in module_node.statements:
      if stmt is assignment or always:
         for (src in stmt.rhs_signals):
            D.add((src, stmt.lhs_signal))
  for each module m:
    signal_chains[m] = backward_trace(IO[m].outputs, D)
    prune_internal(signal_chains[m], IO[m])

3. LLM-Guided Module Specification and Assertion Mining

With per-module structural artifacts established, AssertMiner employs a two-stage LLM prompting pipeline:

  1. Module-Level Specification Extraction:

Each module mm is described via a concise prompt incorporating: - the module and parent name (from GcallG_{call}), - I/O table IO(m)IO(m), - representative simplified signal chains, and - the top-level natural-language specification.

Example prompt:

1
2
3
4
5
6
7
You are given the following module structural summary:
• Module: padder
• Inputs: [clk, reset, data_in]
• Outputs: [data_out, valid]
• Signal chains: clk→pad_state→data_out; data_in→pad_logic→data_out
The top-level design is a SHA3 hash function.
Please infer a concise module-level functional specification for padder, in one or two sentences.

Few-shot in-context examples strengthen generalization and mitigate LLM hallucinations or misattribution of RTL errors.

  1. Feature Decomposition and Assertion Generation:

The LLM further decomposes inferred module specifications into atomic verification features—concise, testable predicates. For each feature, the model generates a concrete SystemVerilog assertion using a unified template:

1
2
assert property (@(posedge <CLK>)
   (<AP1> && <AP2> …) |-> (<AP3> && <AP4> …) );
Atomic propositions like padder.pad_state == 0 or padder.data_out == {data_in, padding} instantiate the placeholders, standardized across assertion outputs.

4. Integration with Assertion Suites

Module-level assertions produced by AssertMiner are designed to complement top-level suites created by methods such as AssertLLM and Spec2Assertion. The practical workflow is:

  1. Run Spec2Assertion for top-level assertions.
  2. Run AssertMiner for module-local assertions.
  3. Aggregate both sets for input into formal property verification tools.

This unified strategy achieves broad functional coverage (via top-level properties) and efficient, localized bug identification (via deep module checks). Experimental measurements report increases in branch and statement coverage metrics (e.g., BFC up to 4.33% improvement for AssertLLM + AssertMiner, SFC up to 5.13% for Spec2Assertion + AssertMiner), with only a modest number of additional assertions introduced (Lyu et al., 13 Nov 2025).

5. Empirical Evaluation and Results

AssertMiner was evaluated on benchmarks derived from IWLS-2005, using designs such as I²C (1282 LOC), ECG (1635 LOC), Pairing (2145 LOC), and SHA3 (618 LOC). Key evaluation criteria include:

Metric Symbol Definition Usage
N Number of generated assertions Overall yield
S Number syntax-correct Filtering syntactic errors
P Number passing FPV (valid) Assertion effectiveness
NVR Non-Violation Rate =PS×100%=\frac{P}{S}\times100\% Assertion precision
BFC Branch Functional Coverage Coverage via JasperGold FPV
SFC Statement Functional Coverage Coverage via JasperGold FPV
TFC Toggle Functional Coverage Coverage via JasperGold FPV

Notably, AssertMiner demonstrated P/N ratios from 46% to 83% and SFC/BFC above 80% across all tested designs (e.g., SHA3: 24 assertions, 20 valid, SFC=82.93%, BFC=80%). Integration with AssertLLM or Spec2Assertion consistently led to higher functional coverage and error-detection rates than standalone use or even manually crafted assertions (mutation-testing gains of 5%–19%).

6. Illustrative Examples

AssertMiner-generated specifications and assertions exemplify deep local semantic capture. For the SHA3 padder submodule:

  • Inferred Specification:

"The padder module initializes on reset, then appends a single ‘1’ bit followed by the minimum number of ‘0’ bits to reach the required block length, asserting valid_out for one cycle."

  • Generated Assertion (SystemVerilog fragment):

1
2
3
4
5
6
7
assert property (@(posedge clk) disable iff (reset)
  (reset == 1) |-> (padder.pad_state == IDLE)
);
assert property (@(posedge clk)
  (padder.valid_in && padder.pad_state != END)
     |-> ##[1] (padder.data_out == {padder.data_in, 1'b1, {padder.pad_count{1'b0}})
);

For an I²C controller:

  • Inferred Specification:

"On start condition, the controller must drive SCL low within one cycle and pull SDA low to transmit the address bit."

  • Generated Assertion:

1
2
3
4
assert property (@(posedge clk) disable iff (reset)
  (i2c.start && i2c.bus_busy == 0)
    |-> ##1 (i2c.SCL == 0 && i2c.SDA == address_bit)
);

7. Limitations and Future Research Directions

AssertMiner's reliance on AST-based extraction is robust to language variations, but scaling challenges emerge for designs with deep or wide hierarchies. Traversal overhead and the complexity of resulting signal-chain summaries can become prohibitive. Inaccuracies in the AST—stemming from nonstandard preprocessing or vendor-specific constructs—could mislead the LLM, providing erroneous prompt contexts.

Potential avenues for future work include:

  • Implementation of hierarchical pruning algorithms to focus the LLM on high-value subgraphs.
  • Augmenting static analysis with simulation-based traces to provide dynamic context.
  • Automated ranking of mined assertions based on novelty or predicted error-detection impact to improve reviewer efficiency (Lyu et al., 13 Nov 2025).

AssertMiner advances the practical automation of module-focused assertion-based verification, closing the specification-to-assertion gap at the micro-architectural level and enabling streamlined, early, and precise RTL bug discovery.

Definition Search Book Streamline Icon: https://streamlinehq.com
References (1)

Whiteboard

Topic to Video (Beta)

Follow Topic

Get notified by email when new papers are published related to AssertMiner.