Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Glossary
  • Metrics Reference
  • Formal Cheat Sheet
  • Formal Foundations19
  • Properties and SVA16
  • Property Development and Constraints19
  • Proof Engines and Convergence23
  • Formal Applications20
  • Equivalence Checking14
  • Formal Coverage and Signoff15
    • Cover Properties, Vacuity and Reachability
    • Formal Coverage Metrics
      • Proof Core and Cone Coverage
      • Assumption Influence and Coverage
      • Mutation-Based Formal Coverage
      • What the Numbers Do Not Say
    • Bounded Proof Signoff
    • The Formal Signoff Package
  • Methodology and Debug13
  • Interview Prep15
  • Capstone: A Chip-Block Verification Lab24
Loading lesson

←Formal Coverage Metrics
  1. Topics
  2. Formal Verification
  3. Formal Coverage and Signoff
  4. Formal Coverage Metrics
  5. Proof Core and Cone Coverage
On this page

    Part 7 of 10, lesson 5 of 15Part 7 of 10/Formal Coverage and Signoff/Lesson 5 of 15All levels

    Proof Core and Cone Coverage

    Distinguish the logic a property could depend on from the logic its proof actually used.

    Why it matters

    A property on one output channel of a four-channel block proves quickly, and the report shows full line coverage of the file. But three channels never influenced the proof, and an entire debug block sits outside every cone. Cone coverage would have shown the gap in one table; line coverage hid it. This lesson defines both terms precisely and computes them on a small netlist you can check by hand.

    The core idea

    The cone of influence of a property is the set of registers and inputs that can affect the checked signals, traced backwards through combinational logic and one step per cycle of history. It is exact: cone reduction removes only logic that cannot affect the property, and it never over-constrains; over-constraint comes from assumptions, which are a different thing. Coverage over proven properties is the union of their cones divided by the design: logic in no cone was never examined by any proof.

    The proof core is smaller: the subset of the cone the proof actually needed. A solver may discharge a property using only part of the cone, for example when a case split makes one path irrelevant. Reporting the core beside the cone shows how much of the possible dependence the proof exercised. A high cone coverage with a shallow proof depth is not strong evidence, as the last lesson of this topic shows.

    Worked example: three properties on a small netlist

    An illustrative seven-block design: blocks b0 to b2 read three inputs and feed the shared block b3, b3 feeds b4, and a separate chain b5 then b6 reads a fourth input. Three properties check the outputs of b4, b6 and b3. The script computes each cone by backward reachability, checks that each proof core sits inside its cone, and reports the union coverage. Then it injects an eighth block, a debug counter that only reads other blocks and drives no checked output, and the coverage drops from 7 of 7 to 7 of 8.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    # illustrative: cone and proof-core coverage on a small netlist
    # blocks and what each block reads (fan-in); outputs checked by p1..p3
    fanin = {"b0": ["in0"], "b1": ["in1"], "b2": ["in2"], "b3": ["b0", "b1", "b2"],
             "b4": ["b3"], "b5": ["in3"], "b6": ["b5"]}
    checked = {"p1": "b4", "p2": "b6", "p3": "b3"}
    
    def cone(net, out):
        seen, stack = set(), [out]
        while stack:
            x = stack.pop()
            if x in seen:
                continue
            seen.add(x)
            stack.extend(net.get(x, []))
        return {b for b in seen if b in net}
    
    def coverage(net):
        cones = {p: cone(net, o) for p, o in checked.items()}
        union = set().union(*cones.values())
        return cones, union, len(union) / len(net)
    
    def cores_ok(cores, cones):
        return all(cores[p] <= cones[p] for p in cones)
    
    cones, union, cov = coverage(fanin)
    assert cones["p1"] == {"b4", "b3", "b0", "b1", "b2"}
    assert cov == 1.0
    # proof cores: the subsets the (illustrative) proofs actually consumed
    cores = {"p1": {"b4", "b3", "b0", "b1"}, "p2": {"b6", "b5"}, "p3": {"b3", "b0", "b2"}}
    assert cores_ok(cores, cones)
    # a core outside its cone means the bookkeeping is wrong: the check must catch it
    assert not cores_ok(dict(cores, p2={"b6", "b2"}), cones)
    # inject an unobservable debug block: it reads b4 and b6 but drives no checked output
    with_dbg = dict(fanin, dbg=["b4", "b6"])
    cones2, union2, cov2 = coverage(with_dbg)
    assert abs(cov2 - 7 / 8) < 1e-9
    assert set(with_dbg) - union2 == {"dbg"}
    print("PASS: cone coverage 7/7, then 7/8 with injected block dbg uncovered; bad core rejected")

    The debug block sits in no cone: no property can see it. The fix is a property on its outputs or a documented reason it needs none, never a wider netlist. The subset check runs in one direction on purpose: a core outside its cone means the bookkeeping is wrong, not that the proof saw more, and the script shows the check rejecting such a table.

    What the reviewer looks for

    • Every property reports its cone size, and the size matches the expected logic: a surprise means a disconnected check or a missing path.

    • The union coverage names each uncovered block, and each has a property or a written reason.

    • Core and cone are both reported; a core much smaller than its cone invites the question of what was left unexercised.

    Verify and debug

    A property that proves instantly with an empty or tiny cone is disconnected: the checked signal was optimised away, the hierarchy path is wrong, or an unused signal is named. Mutate a signal inside the expected cone and rerun: if the property still passes, the cone report was telling the truth and the property looks elsewhere. Always confirm the cone before celebrating the speed.

    The silently empty cone: symptom is a property that proves instantly with no flops in its cone. Cause is a disconnected assertion, such as a check on an optimised-away net or a wrong hierarchical path. Fix is a per-property cone report reviewed against the expected logic, plus a mutation of a signal in the cone. It is found by the cone size column, which must never be blank.

    Expect the probe: your suite reports full coverage, what did the proofs actually touch? Answer with the union of cones, the uncovered list, and one core-versus-cone pair where the proof used half of what it could depend on. Full line coverage with half the design outside every cone is the counterexample you carry.

    Check yourself Two properties have identical cones but very different cores. What does that tell you?

    Both can see the same logic, but one proof exercised much less of it. The small-core property deserves a harder look: a case split or an assumption may have excused most of its cone without anyone noticing.

    Related topics

    • Next: Assumption Influence and Coverage

    • Formal: Cone of Influence

    Previous

    121 / 183

    Next: Assumption Influence and Coverage

    Up next

    Up nextAssumption Influence and Coverage

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Mutation-Based Formal Coverage
    • What the Numbers Do Not Say