vj-sim 0.3.0

Netlist, scheduler and process model of the vj SystemVerilog simulator.
Documentation
//! Deferred immediate assertions' reports (LRM 1800-2023 §16.4).
//!
//! A deferred assertion (`assert #0 (...)`, `assert final (...)`) evaluates
//! where it executes, but its action -- with its arguments' values as of
//! then -- reports later: a `#0` one in the Reactive region, a `final` one
//! in the Postponed region of the same time step. The action's output is
//! captured when it executes (`vj_runtime::display_sink`'s
//! `sv_rt_deferred_*`) and held until then, discarded instead if the
//! process resumes first (a flush point, §16.4.2: an always block
//! re-triggered by a glitch) -- so only the evaluation a time step settles
//! on reports, and executing the same assertion again replaces its pending
//! report.
//!
//! **sva T2 (§1.4):** this module is now a thin instantiation of the
//! generalized [`crate::sched::maturation`] queue -- the exact mechanism
//! above, factored out so later report kinds (procedural concurrent
//! assertions, property pass/fail, sequence cover matches, checker action
//! blocks) reuse it instead of a third divergent copy. This module's own
//! public functions keep their exact pre-T2 signatures and behavior (a
//! pure refactor, regression-tested by the unchanged `deferred_assertions.
//! sv` probe-corpus fixture): they are one-line forwards into
//! `maturation::{report, flush, set_writer}` pinned to `ReportKind::
//! DeferredImmediate`.

use vj_abi::Region;

use crate::sched::ProcessId;
use crate::sched::assert_control::SiteId;
use crate::sched::maturation::{self, ReportKind};

/// Sets where matured reports are written (the run's output buffer).
pub fn set_deferred_writer(f: fn(&[u8])) {
    maturation::set_writer(ReportKind::DeferredImmediate, f);
}

/// Holds `text`, the output of the assertion at source offset `site` that
/// the running process just executed, until the Reactive (`final`: the
/// Postponed) region of this time step.
pub fn deferred_report(site: u64, is_final: bool, text: Vec<u8>) {
    deferred_report_for(site, is_final, text, None);
}

/// [`deferred_report`] of the assertion registered as the control site
/// `control` ([`crate::sched::assert_control`]), so that `$assertkill` can
/// discard the report while it is pending (LRM 20.11).
pub fn deferred_report_for(site: u64, is_final: bool, text: Vec<u8>, control: Option<SiteId>) {
    let region = if is_final {
        Region::Postponed
    } else {
        Region::Reactive
    };
    // Every execution is its own pending report (16.4.1: the report is "placed
    // in a deferred assertion report queue"): the same assertion executed twice
    // between flush points (a loop, a function called twice) matures twice.
    let _ = site;
    maturation::report_independent_for_site(ReportKind::DeferredImmediate, region, text, control);
}

/// Discards `proc`'s pending reports (it reached a flush point).
///
/// **sva T2:** forwards to [`maturation::flush`], which discards `proc`'s
/// pending reports of EVERY kind, not only `DeferredImmediate`'s -- see
/// that function's own doc comment for why this is behavior-preserving
/// (only `DeferredImmediate` is reported anywhere in this tree today) and
/// why it is in fact the semantically correct generalization (16.4.2's
/// flush-point rule is process-level, not report-kind-specific).
pub(crate) fn flush_deferred(proc: ProcessId) {
    maturation::flush(proc);
}

/// `disable <deferred assertion label>` (LRM 16.4.4): cancels the running
/// process's pending reports of the assertion registered as the control site
/// `control`. Other processes' reports of it stay (16.4.5).
pub fn deferred_cancel_for(control: SiteId) {
    if let Some(proc) = crate::sched::current_process() {
        maturation::flush_process_site(proc, control);
    }
}

/// A deferred assertion whose action is a call of a user task or void function
/// (LRM 16.4.1): the call -- `thunk(handle, args)`, `args` the argument values
/// captured now -- is made when the report matures (a `#0` one in the Reactive
/// region, a `final` one in the Postponed region), and never if the running
/// process reaches a flush point first (16.4.2). `control` is as in
/// [`deferred_report_for`].
pub fn deferred_call_for(
    is_final: bool,
    thunk: usize,
    handle: usize,
    args: &[u8],
    control: Option<SiteId>,
) {
    let region = if is_final {
        Region::Postponed
    } else {
        Region::Reactive
    };
    maturation::report_independent_for_site(
        ReportKind::DeferredCall,
        region,
        maturation::call_payload(thunk, handle, args),
        control,
    );
}