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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
//! A2-PROCESS (`sv-sim-sim::process`) — cross-track contract only: the process
//! template lowering shape shared between the A2-process track and CODEGEN
//! (process.md). Real liveness analysis / CFG construction belongs to the
//! A2-process track, not this wave.
use ;
use crateJoinKind;
use crate;
// Task S3a (CPS CFG + Segment IR) touches `sv_lang::Statement`/`Expression`
// directly, so it lives behind this crate's `frontend` feature per
// `docs/CONTRACTS.md` D4 -- unlike the plain POD shape types above, which
// stay sv-lang-free and ungated.
// Task 7 (PR-116, XC-044): re-exported at this module's own path (rather
// than only `process::cfg::`) so `suspending_statement_kinds` sits exactly
// where the plan names it (`sv-sim-sim::process`) -- physically defined
// next to `SuspendPoint` in `cfg` (see that function's own doc comment for
// why), not redeclared here.
pub use ;
// Task S3b (Liveness + FrameLayout) touches `sv_lang::Symbol`/`SymbolId`
// directly (declared-local discovery via `Statement::block_symbol()` +
// `Symbol::members()`), so it lives behind this crate's `frontend` feature
// for the same reason `cfg` does -- see `cfg`'s doc comment above.
// Task S5 (Template dedup + `ProcessInstanceId`) touches `sv_lang::Symbol`/
// `SymbolId`/`ConstantValue` directly (`Symbol::parameters()`,
// `instance_body_definition()`, `constant_value()`), so it lives behind this
// crate's `frontend` feature for the same reason `cfg`/`liveness` do -- see
// `cfg`'s doc comment above.
/// Stable, elaboration-order-derived tie-break key (process.md §6: "derived from
/// a deterministic pre-order walk of the frozen Design's instance hierarchy,
/// never from allocation order or thread arrival"; ledger PR-075..PR-077,
/// PR-118, DT-011, DT-031). The scheduler consumes this as its canonical
/// cross-thread tie-break.
;
/// Opaque, minted 1:1 by CODEGEN per trap-eligible statement at lowering time
/// (debugger.md; ledger CG-142, CG-149, CG-154, SC-104, SC-126, DB-034): stable
/// only within one compile, never across recompiles (no hot-reload of source into
/// a live debug session).
;
/// One frame slot's compile-time SHAPE only (process.md §3 `FrameSlot`/
/// `FourStateI2N`/`WideFourState`; ledger ST-103..ST-105): the number of u64
/// words the slot's payload occupies. This is layout metadata CODEGEN consumes
/// when computing a TEMPLATE's fixed frame offsets ("Frame slot layout is
/// decided once per process TEMPLATE... handed to codegen as a fixed struct
/// layout") — never the runtime payload itself, which is why it carries
/// counts, not `Vec<u64>` data (see [`ActivationRecord`]'s doc comment for why
/// that distinction is load-bearing).
/// A fixed, pointer-free reference to a contiguous range of STATE-owned arena
/// storage (word- or element-addressed, per the referencing field's own unit).
/// Never an owning buffer — the one shape every [`ActivationRecord`]-embedded
/// field below uses in place of a heap-owning `Vec`.
/// POD, pointer-free, memcpy-checkpointable — the only per-instance execution
/// state that must survive a suspend or a Time-Warp rollback (process.md §3;
/// ledger CG-164, CG-176, ST-005).
///
/// Fixed vs. an earlier draft of this contract (caught in review): storing
/// `frame: Vec<FrameSlot>` / `pending_wait: Option<WaitSpec>` (its `EdgeList`
/// variant owns a `Vec`) / `fork_state: Option<ForkFrame>` (its
/// `child_handles` owned a `Vec`) directly here made the "memcpy-
/// checkpointable" claim false — a `Vec` is a heap pointer + len + cap, so
/// byte-copying this struct for checkpoint/rollback would duplicate that
/// pointer, and dropping or mutating either copy double-frees or
/// use-after-frees the other. `frame: [FrameSlot]` in
/// `docs/design/process.md`'s own struct sketch (§3, line 40) is a DST slice,
/// meaningful only as a *reference* into memory STATE owns ("owned/allocated
/// by STATE, laid out by this subsystem via FrameLayout") — never data this
/// struct owns inline. `frame` below is exactly that reference: an
/// [`ArenaRange`] into STATE's per-process frame arena (word-addressed); the
/// per-slot shape list (`FrameLayout`/`Vec<FrameSlot>`) stays a compile-time-
/// only artifact of `ProcessLoweringPlan`, analogous to `state::SlotOffset`,
/// and is never embedded in the per-instance runtime record. `pending_wait` /
/// `fork_state` are fixed for the same reason — see [`WaitSpecStorage`] /
/// [`ForkFrame`]'s own doc comments.
// No `PartialEq`/`Eq`: transitively embeds `PredicateFn` (a bare fn pointer,
// whose equality is deliberately not derived -- see `PredicateFn`'s own doc
// comment). `Copy` is what the POD/memcpy-checkpointable contract needs.
/// The POD cache of the last-returned suspend reason, embedded directly in
/// [`ActivationRecord`]. `docs/design/process.md` §3/§4 names this exact
/// split: the persisted field is `WaitSpecStorage`, distinct from the richer
/// [`WaitSpec`] the suspend/resume ABI exchanges with the scheduler on every
/// call ("last-returned WaitSpec, re-derivable but cached for O(1) resume
/// dispatch and for the debugger inspector"). `Edge`'s single term is already
/// `Copy` (`PredicateFn` is a bare `extern "C"` fn pointer) so it is inlined
/// directly; `EdgeList`'s term count is unbounded (an arbitrary-length
/// `@(a or b or c or ...)`), so like `ActivationRecord::frame` it is instead
/// an [`ArenaRange`] into a static, elaboration-time-built edge-term table
/// (the concrete `StateCellId`s for a given suspend point are fixed once
/// elaboration resolves the instance's signals and never change for the life
/// of the run, so this table is a read-only lookup, never a rollback hazard).
// No `PartialEq`/`Eq`: the `Edge` variant embeds `Option<PredicateFn>` -- see
// `PredicateFn`'s own doc comment for why fn-pointer equality isn't derived.
/// Fork/join bookkeeping (process.md §7: "construction only, no scheduling
/// semantics in v1"; ledger PR-086, fork/join family PR-001, PR-047, PR-061).
/// `children` is a fixed [`ArenaRange`] into the engine's dynamic fork-child
/// table — never an owned `Vec`, the same memcpy-safety reason as
/// `ActivationRecord::frame`. Its elements are [`crate::sched::ProcessId`],
/// **not** [`ProcessInstanceId`]: scheduler.md is explicit that "fork
/// children are dynamically created ProcessIds not present in static
/// elaboration," so `ProcessInstanceId` (elaboration-derived, static-only per
/// this file's own doc comment above) structurally cannot name them. The
/// branch *count* for a given fork site is statically known at lowering time;
/// the concrete `ProcessId`s are assigned dynamically at fork time and live
/// in that out-of-line table, never inline here.
/// The settled `CondThunk` shape for a `SignalEventControl`'s `iff` re-check
/// AND `wait(expr)`'s own re-check (PR-106, A2-part2 Task 3): a plain
/// `extern "C"` function pointer over the shared `SimHandle`, produced by
/// exactly one compiler entry point, `sv-sim-codegen::process_lower::
/// compile_iff_guard` -- see that function's own doc comment. Through Task 1
/// this shape was left an open question (process.md: "needs to be settled
/// jointly with codegen's dispatcher shape... not decided unilaterally
/// here"); Task 3 settles it: a raw function pointer into a standalone,
/// independently-compiled guard function, never a re-entry into a dedicated
/// micro-segment.
// Deliberately no `PartialEq`/`Eq`: fn-pointer comparisons are not
// meaningful (address is not guaranteed stable/unique across codegen units,
// merged identical functions can collide) -- `rustc` warns on this
// (`unpredictable_function_pointer_comparisons`). `Copy` alone is what the
// POD/memcpy-checkpointable contract actually needs.
);
/// A precomputed, static subscription-set id for `always_comb`/`always_latch`'s
/// implicit sensitivity (scheduler.md §4/§5) — O(1) resubscribe, computed once
/// ever from `AnalyzedProcedure::read_set()`.
;
/// The ABI-facing resume contract (process.md §4 `WaitSpec`; ledger CG-169,
/// CG-170, SC-085, SC-119, PR-012, PR-037) a compiled process kernel reports back
/// through [`ProcessStatus::Suspended`].
///
/// Reconciliation: distinct from [`crate::sched::Suspend`]. `sched::Suspend` is
/// the Rust-trait-level abstraction `CompiledProcess::resume()` returns to the
/// *in-process* scheduler orchestration loop (scheduler.md §5); `WaitSpec` here is
/// the lower-level, codegen-facing shape process.md §4 sketches for the compiled
/// `process_kernel`-style ABI. ARCHITECTURE.md does not collapse the two designs'
/// differing field lists into one type, so per the reconciliation rule both are
/// kept, layered rather than merged: `sched::Suspend` is built by decoding a
/// returned `WaitSpec`/`RescheduleReq`, not by replacing it.
/// What woke a process (process.md §4 `ResumeInfo`/`ResumeReason`).
/// The compiled-kernel calling convention every process TEMPLATE compiles to
/// (process.md §4). **Not** the literal ABI-crossing symbol — that is
/// [`sv_sim_abi::ProcessFn`] (`extern "C"`, using the frozen `SimHandle`/
/// `EvalResult`/`RescheduleReq` shapes so every field stays FFI-safe). This is the
/// richer, process-track-internal Rust-level decoding of that call, matching
/// process.md's own explicitly-flagged scope ("proposed here at the logical
/// (Suspend/ResumeArg) level only; the physical ABI needs to be pinned jointly
/// with CODEGEN") — an ordinary Rust `fn` pointer, deliberately not `extern "C"`,
/// since [`ProcessResult`] owns a heap-allocated field (`WaitSpec::EdgeList`'s
/// `Vec<..>`, via `ProcessStatus::Suspended`) that is not FFI-safe by value.
/// [`ActivationRecord`] itself is `#[repr(C)]`/POD (see its own doc comment) —
/// it is the *return type*, not the activation pointer, that blocks
/// `extern "C"` here.
pub type ProcessKernelFn =
fn ;
/// Rollback-safety classification per `LoweredStmt`/`Segment` (process.md §6),
/// consumed by the engine's Time-Warp commit policy.
/// Task 10 (A2-part2, PR-122): the per-partition additive bias CODEGEN adds
/// to a `SignalSlot::slot` arena-slot integer operand before it reaches
/// `accessor::build_get_scalar`/`build_set_scalar`, so two processes in
/// different WOCB partitions (`region_id`s) address disjoint arena-base
/// bands: partition `region_id`'s slots occupy `[region_id *
/// slots_per_region, (region_id + 1) * slots_per_region)`. A plain multiply,
/// not a hardcoded zero -- `region_id == 0` (v1's only real value) yields
/// `0`, leaving every real accessor call's slot operand byte-identical to
/// today's unbiased value (this task changes zero observable behavior for
/// any real v1 design); a caller that hand-sets a synthetic `region_id >= 1`
/// (no such partition exists yet -- the WOCB analysis pass that would assign
/// one is unbuilt) gets a real, disjoint, nonzero band, which is exactly
/// what the codegen-side IR-inspection test proves. One definition, reused
/// by both the real biasing call site (`sv-sim-codegen::process_lower`'s
/// `prime_external_signals`/`flush_external_signals`) and this task's own
/// unit test -- never reimplemented a second time.