Repository navigation
feat!: share native trigger execution with coverage bins - #30
Merged
Merged
Conversation
XData accesses signal buffers through both 32-bit and 64-bit views. GCC 11 Release builds with -O3 and LTO can treat these accesses as independent and return stale values after Set(), breaking the full-value wheel smoke test. Compile native targets and standalone wheels with -fno-strict-aliasing while preserving -O3, LTO and the existing optimization flags. Add integer round-trip and unknown-bit mask regressions across 1-64-bit signals, with checks that remain active under NDEBUG.
Read 1-8-bit and 9-16-bit native bindings at their actual storage width instead of reading a full 32-bit word. Make range comparisons read only the configured 1-8 bytes and support unaligned addresses. Select the comparison width when creating the callback; fixed-size copies inline to one load per input for 1/2/4/8 bytes, or two overlapping loads for 3/5/6/7 bytes, without per-call allocation. Avoid shifting by 64 during signed conversion and signed overflow when constructing 31-bit masks. Treat out-of-capacity word offsets in SetBits as empty writes. Handle oversized shifts and INT_MIN in big_shift using unsigned arithmetic and zero-fill results outside the buffer width. Add exact-allocation, unaligned-input, slice, signed-value, masked-write and shift-boundary regressions, and document the pointer comparison and SetBits bounds. Public signatures and native class layouts retain ABI 2. Validation of the complete series: - GCC 11 Release: all 7 native tests and the Python suite pass. - ASan/UBSan: all 7 native tests pass (-O1, no LTO or leak detection). - Picker integration: all 24 CTest cases, Java bindings and 11,451 generated Adder vectors pass, including ABI 2 signal checks. - Local x86_64 callback benchmarks match baseline checksums; non-power- of-two widths add approximately 0.2-0.8 ns per comparison in this setup.
Compare range-check buffers wider than 64 bits and use the complete XData signal width, with unsigned zero extension for operands of different widths. Compute word-wise differences with borrow and exact-size unaligned loads; retain the scalar fast path and avoid per-comparison allocation. Reject X/Z operands and refresh each signal once without writing to its backend. Prevent tolerance checks from wrapping at zero or UINT64_MAX, including negative ranges and INT_MIN. Add regressions for 9-33-byte buffers, 65-256-bit signals, cross-word borrow, unknown bits and callback read/write counts. Unify BindNativeData vector reads and writes in a typed memcpy helper with explicit C++ casts. Generate the 1-16-word fixed-count binding cases with an X-Macro and use a runtime loop for longer vectors. Preserve current bval behavior and document the unresolved native X/Z policy. Keep callbacks tied to the current word count so ReInit can change widths without stale accesses. Cover exact-size unaligned native buffers, all fixed-count paths, the runtime threshold, preserved unknown masks and ReInit growth/shrink transitions. Public API signatures and native class layouts retain ABI 2. Validation of the final tree: - GCC 11 Release: all 7 native tests and the Python regression suite pass. - ASan/UBSan: all 7 native tests pass, with leak detection disabled. - C++17 syntax check and git diff --check pass. - Local x86_64 full U()/Set() benchmarks: 2 million iterations, 7 samples per round, 3 rounds with alternating order on the same CPU. Checksums match; 8-64-bit timings stay within 2%, while 256-bit read/write times fall about 16%/10% and 1024-bit times fall about 35%/23%.
Split ComUse declarations into callback, condition, range, and utility headers under xspcomm/xcomuse/, with xcomuse.h as the aggregate entry point. Remove xcomuse_base.h and migrate expression and test includes to explicit dependencies. Preserve class layouts and existing callable APIs. Move range comparison internals into xcomuse_range.cpp. Express fixed-width reads through UIntWord/UIntParts specializations, using exact-length memcpy loads without overlapping reads or unaligned typed pointer dereferences. Retain callback selection at registration and full-width borrow comparison. Update the shared SWIG interface and recursively track component headers for Python wrapper regeneration. Move unresolved BindNativeData X/Z policy notes from the API reference to developer documentation without changing bindings. Validation: - C++17/C++20 standalone and mixed inclusion of seven public headers - Release and ASan/UBSan: all seven CTest targets pass in each build - Python suite and 4,000 arbitrary-precision comparison cases pass - Public Python exports and class sizes/alignment match the previous build - Client compiles and runs using only staged headers and the built library
Group native sources by core, common, expression, ComUse, trigger, and coverage responsibilities. Split XData implementation files and move third-party headers, language binding tests, and TLM integration sources out of the public SDK and production test code out of the shared library. Share comparison helpers between XData and ComUse checkers. Extract sequence/FSM matching for reuse by trigger and coverage, and give coverage its own sampling state, counters, bins, crosses, gates, and diagnostics. Keep trigger coverage entry points as small adapters and avoid copying pattern descriptions or adding allocations during sampling. Separate expression engine headers from checker adapters, move utilities to common headers, and update include paths directly without legacy forwarding headers. Keep runtime class layouts and Python public methods. Centralize native and JavaScript source lists, stage only current public headers, register tests at the build root, and install the standalone TLM source SDK under share/xspcomm/tlm. Update SWIG interfaces, package contents, and architecture documentation for the new layout. Validation: Release build and all 9 C++ tests plus Python regression passed from the actual workspace. The identical proposal also passed ASan/UBSan, 50 standalone C++17/C++20 header checks, layout and behavior comparisons, all six SWIG generators, and clean wheel/sdist installation checks. VCS/SystemC and Emscripten execution were unavailable locally.
Extract generic condition and pattern matching from coverage into the Trigger module. Reuse sequence/FSM advancement with ordinary triggers, and keep overlap attempts, completion counts and terminal filtering in a reusable PatternMatcher. Coverage retains gating, reset/abort handling, bin classification and statistics. Support Expr, Sequence and FSM programs on pattern coverpoints. Equivalent bin programs within one coverpoint share one execution while preserving independent terminal selection, hit thresholds and counters. Keep executions independent across coverpoints and expose CoverageExecutionCount for validation. Add focused matcher and coverage regression tests, and document the execution boundaries and protocol. Inline small helpers to avoid additional calls on the sampling path. Validation: - 10 native C++ test targets pass in Release and with ASan/UBSan. - 1,021 experimental XReactor tests pass against a clean installed wheel. - 8,192 legacy sampling steps and 256 stale-handle cases match the baseline. - C++17/C++20 headers, six SWIG generators, TLM wrapper and installed SDK pass. BREAKING CHANGE: extended XCoverageBin descriptors change the public C++ layout. Raise native ABI to 3 and CoverageVersion to 4; consumers must rebuild and update compatibility checks for the new ABI and coverage protocol.
Makiras
commented
Oct 10, 2026
Expose XEngine as the common sampling runtime, with coverage bins composed from shared trigger programs and matchers. Retain the XTriggerEngine source alias and preserve its name in generated language bindings. Separate coverage item kinds from bin policies, move implementation headers under detail/, and split reusable memory access from comparison operations. Unify ComUse expressions and conditions, track attached callback lifetimes, and retain alignment-safe native memory access without per-sample allocation. Keep expression matching on a lightweight shared path, move optional coverage diagnostics out of the hot path, pre-index illegal bins, and inline condition evaluators. Skip unused wall-clock sampling when RunUntil has no time budget. BREAKING CHANGE: raise the native ABI to 4 and coverage protocol to 5. Native consumers must rebuild; coverage descriptors now use explicit item/bin kinds and embedded trigger programs. Publish the preview as 0.3.0.dev1. Validation: - Release C++: 10/10 suites passed. - ASan/UBSan C++: 10/10 passed at O1 without LTO; leak detection disabled. - Python: 1021 tests passed against the benchmarked native library. - Differential: 8192 samples and 256 stale handles match the baseline exactly. - Three alternating local benchmark rounds: expression coverage is about 3% faster, and 16-bin Sequence/FSM coverage is about 14%/15% faster than 83ab5b2. The ordinary Edge microbenchmark remains about 2.5% slower than that baseline.
Rename xcomuse to xmonitor and replace ComUse classes with the XStepCallback, XConditionCheck, XExprCheck, XRangeCheck, XFsmMonitor, XEcho and XByteBuffer names across C++, SWIG bindings, tests and documentation. Expose CompareOp consistently and remove the old paths and names without compatibility aliases. Group common comparison, memory, callback-storage and lifetime helpers under include/xspcomm/common. Move trigger matching, coverage state and native-memory implementation headers beside their sources; keep source include paths private to the library, JavaScript source build and implementation tests. Extract phases, handles and sampling results into runtime/types.h independently of XClock. Forward-declare XEngine's private Watcher and define it under src/runtime, retaining contiguous registration storage and inline matching. Group XData implementations under src/data and align executor/state filenames with their responsibilities. Update SDK staging, migration and maintainer docs. Bump the native ABI from 4 to 5 for renamed exported symbols; retain coverage descriptor protocol 5 and document the coordinated 0.3.0.dev2 migration. Validation: - Release and ASan/UBSan native suites: 10/10 each. - Python binding checks and xreactor frontend suite: 1021 frontend tests passed. - 70 standalone C++17/C++20 header checks; all six SWIG interfaces generated. - Installed-SDK consumer and TLM wrapper compiled; SDK consumer ran successfully. - Public type sizes/alignment and randomized trigger/coverage outputs unchanged. - Five local matching/coverage benchmarks changed by -1.36% to +2.19%. BREAKING CHANGE: Native consumers must rebuild against ABI 5, and source and binding clients must migrate the removed ComUse names and header paths.
Rename XCoverageItem, its kind enum and binding vector to XCoveragePoint, and identify each bin's parent with point_id. Update native coverage state, registration, bindings, tests and migration documentation together. Add explicit AcquireClock/ReleaseClock ownership for an entire execution, including pauses between RunUntil calls. Reject competing engines, manual stepping, reset, reinitialization and copying of an owned clock. Keep idle clock initialization and copying available, preserve phase on release, and require registrations to be disarmed before release. Release ownership on engine destruction, detect clocks destroyed first, and reject recursive runs or clearing/releasing a running engine. Guard legacy Python clock wait/run helpers and restore callback state on errors. Consolidate the unpublished branch to native ABI 3 relative to master's ABI 2. Keep coverage descriptor protocol 5 independent of the native ABI. Validation: Release CTest 10/10; 118 xreactor integration tests using ABI 3; verified libxspcomm.so.3 SONAME and Python extension linkage. The runtime implementation also passed ASan/UBSan 10/10, full xreactor 932 tests and 1026 tests in the isolated coverage-v2 frontend before ABI renumbering.
6 of 8 tasks
Retain active trigger and coverage roots during expression collection, preserving matcher state and counters. Add fixed-width signed arithmetic and casts to ExprEngine using existing XData and comparison helpers. Reuse typed evaluation buffers and evaluate shared DAG nodes once per call. Validate with 11 native tests, 1104 xreactor tests, a rebuilt Picker Adder DUT, and 5000 warm evaluations with zero heap allocations.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Coverage bins consume complete expression, Sequence and FSM trigger programs through the same native validation and matching kernel as ordinary triggers. Equivalent programs within one coverage point share execution while each bin retains its terminal selection, threshold, classification and counter. Matching runs in the native sampling phase without per-hit Python callbacks.
XEngine schedules the clock phases and registration lifecycle for both trigger events and coverage statistics. An engine explicitly acquires exclusive control of its XClock; manual Step, StepHalf and RunStep calls, competing engines and incompatible clock mutations are rejected until release. Ownership persists across paused/batched execution, requires disarmed registrations before release, and is cleaned up when the engine is destroyed. Constructing an idle engine still permits ordinary DUT initialization.
The complete branch also:
Compatibility and release intent:
Validation:
Supersedes #29 following the branch rename to xreactor-coverage-v2. Existing commits and review history are preserved. This PR is not merged and no release tag is created by updating its description or labels.