Skip to content

feat!: share native trigger execution with coverage bins - #30

Merged
Makiras merged 10 commits into
masterfrom
xreactor-coverage-v2
Oct 22, 2026
Merged

Makiras merged 10 commits into
masterfrom
xreactor-coverage-v2

Conversation

@Makiras

@Makiras Makiras commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

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:

  • Reorganizes public headers and implementation into core/data, common utilities, monitor, trigger, coverage, runtime and TLM modules. Tests and private implementation headers are outside the installed SDK. Removed names and header paths have no forwarding compatibility wrappers.
  • Replaces XCoverageItem with XCoveragePoint, including kind/vector names and bin.point_id. Descriptors explicitly distinguish Value, Pattern and Cross points and carry bin.program.
  • Fixes optimized native signal reads/writes, exact-size and unaligned buffers, integer/shift boundaries and comparisons wider than 64 bits.
  • Generates the 1–16-word native binding specializations with one X-Macro and uses a shared loop for longer vectors, retaining native execution without per-step Python dispatch.
  • Exposes CoverageExecutionCount for checking point-local program sharing and keeps ordinary trigger history independent from coverage registrations.

Compatibility and release intent:

  • Use release:major for the package release. Package version, native ABI and coverage descriptor protocol are separate identifiers.
  • Native ABI remains 3 relative to master ABI 2; the unreleased branch changes are consolidated into that ABI. Coverage descriptor protocol is 5. Native clients and generated DUT extensions must rebuild against matching headers/runtime, and source consumers must migrate removed names/paths.
  • The paired Picker #115 targets master with release:minor and updates the source pin, ABI/protocol checks, generated DUT regression and TLM SDK paths. Its current xspcomm<0.4 development requirement must be aligned with the planned xcomm major release before Picker merges/releases. Publish the compatible xcomm release first.
  • Arbitrary Python-predicate native bins and temporal crosses remain outside this implementation. The paired main XReactor frontend adaptations are local separate work; they are not published by this PR.

Validation:

  • All 10 native xcomm C++ targets pass in Release and under ASan/UBSan.
  • The combined isolated Picker/xcomm build passes all 27 native CTest targets.
  • Real generated Adder tests pass in Python and Java. The Python regression checks DUT-level manual stepping rejection, competing engine ownership, native trigger execution, coverage counters and release back to manual stepping.
  • A clean xspcomm 0.3.0.dev2 preview wheel paired with the Picker development wheel passes offline installation, ABI 3/protocol 5 and ownership checks.
  • 932 tests in the local paired main XReactor frontend pass against the newly built xcomm wheel.
  • Previous branch validation covered the experimental frontend, legacy sampling/stale handles, C++17/C++20 headers, all six SWIG generators, TLM, installed SDK packaging and sampling benchmarks.

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.

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 Makiras added enhancement New feature or request release:minor Minor release after the PR merges labels Oct 9, 2026
Comment thread include/xspcomm/common/compare.h
Comment thread include/xspcomm/common/memory.h Outdated
Comment thread include/xspcomm/monitor/callback.h
Comment thread include/xspcomm/xcomuse/condition.h Outdated
Comment thread include/xspcomm/monitor/expr.h
Comment thread include/xspcomm/xutil.h
Comment thread src/data/backends.cpp
Comment thread src/trigger/engine.cpp Outdated
Comment thread src/trigger/matcher.h
Comment thread src/pattern.cpp Outdated
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.
@Makiras Makiras added release:major Major release after the PR merges and removed release:minor Minor release after the PR merges labels Oct 12, 2026
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.
@Makiras
Makiras merged commit a5f5dae into master Oct 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request release:major Major release after the PR merges

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant