Repository navigation
Conversation
Process kernels could only suspend for a time. Add waits whose condition the kernel evaluates itself, and lower SystemVerilog timing controls to them, so `initial` blocks and `always` processes with `#delay`, `@(event)` and `wait (condition)` simulate (#1123, phase 1). - `ProcessStatus::Wait` reports a suspension at an event or level wait; `Pending` reports a resumed check whose condition does not hold yet. `ProcessKernelBuilder::begin_wait` and `wake_if` build such a wait. - The timed scheduler keeps the waiting processes and runs them, with the processes that resume at a time, in declaration order, repeating the pass while one ran. A process another one wakes therefore runs before the registers of that time evaluate, as in the active region of IEEE 1800-2023 and as Icarus Verilog orders it. A round in which every waiting process is pending ends the time. `Simulation::step` and `run_until` poll the waiting processes first, so host writes wake them. Checkpoints and schedule parts carry the waiting set. - The SV analyzer converts delay controls, event controls (`posedge`, `negedge`, any change, `or` and `,` lists) and `wait` statements, and classifies an `always` with a leading delay, a level-sensitive list or timing inside an edge-sensitive body as a process that restarts its statement forever. The lowering samples event expressions into hidden state, detects edges on the least significant bit including transitions through unknown values (not between `x` and `z`), and converts unknown delay amounts to zero. Tasks with timing controls run inline in processes. - Update the sv-tests expectations: five chapter-9 cases now elaborate.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f6e6cf04f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Merging this PR will not alter performance
|
…stored Instruction selection sliced a value loaded from sim state by loading the sliced range from memory again, also when a Store to that address came between the Load and the Slice, so the slice saw the new memory instead of the loaded value. The reload shortcut now applies only while nothing in the block wrote the address since the Load; otherwise the register is sliced.
- Record the events a kernel's store makes to a variable some process waits on in hidden counters, so an event a later store of the same run hides (a value written and restored) still wakes the waiter. - Give each process its own copies of the formals and locals of the subroutines it calls that suspend, mapped at the address level in the lowering, so concurrent activations of a timed task do not share them. - Classify an edge-sensitive `always` that reaches a timing control through a task as a process. - Drain the remaining rounds of a time in `settle_at`, as `step` does. - Reject nonblocking assignments in the tasks a process calls.
There was a problem hiding this comment.
💡 Codex Review
celox/crates/celox-runtime/src/simulation.rs
Lines 499 to 501 in 74fd210
When a process performs multiple blocking writes to a clock before suspending, this final-value comparison loses clock edges just as it would lose an event occurrence. For example, #1 clk = 1; clk = 0; #1; leaves value == before, so no trigger is marked and an always_ff @(posedge clk) block never runs, although the positive edge occurred. Process stores to clock/reset domains need to retain edge occurrences while the kernel executes rather than deriving them only from the final value.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The reload shortcut of a Slice compared the stored address with the loaded one, but distinct state addresses may alias one physical range. The block's writes are now tracked as physical byte ranges (value and mask planes), and the loaded range is checked for overlap.
- Watch every event expression a process waits on, not only identifiers: a kernel's store to a variable the expression reads snapshots the expression before the store and counts the change, rise or fall it made. - A process with private copies of a watched variable (the formals of an automatic task) keeps its own counters for that watcher. - Carry the `automatic` lifetime (the subroutine's keyword or the module's default) into the IR and privatize only automatic subroutines: a static task shares its formals and locals between activations. - Classify an edge-sensitive `always` that calls an imported timed task as a process: the imported subroutines' bodies join the timed-task set.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5ba0009d6f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Address the third review round of the process kernels. - An event expression that calls a function is watched too: the watcher depends on what the function (and its callees) reads besides the expression's own identifiers, so a store a function result hides still wakes `@(f(a))`. The stores of the recording itself are not recorded. - `package automatic` gives the tasks it exports the automatic default lifetime, as a `module automatic` header does. - `settle_at` runs the processes due at its time, after stepping the events and wakeups due before it at their own times. - `Simulation::step` returns the current time when a host write woke a process, instead of also advancing to the next scheduled time in the same call, so what the process did is observable at its own time.
There was a problem hiding this comment.
💡 Codex Review
celox/crates/celox-runtime/src/simulation.rs
Lines 510 to 512 in 5196086
When a timed process performs multiple blocking writes to an event signal before suspending, this comparison observes only the value before and after the entire kernel run. For example, #1 clk = 1; clk = 0; leaves value == before, so an always_ff @(posedge clk) is never triggered even though the first assignment produced a posedge. Fresh evidence beyond the earlier event-waiter fix is that those counters wake process kernels only; sequential domains still rely on this final-value comparison. Retain each edge produced by process stores when marking triggered domains.
celox/crates/celox-runtime/src/simulation.rs
Lines 704 to 706 in 5196086
In the component-testbench path, step_process_events schedules a clock/reset edge for its requested timestamp and then calls state.step(sim) once. With this new minimum, if an RTL process has a wakeup earlier than that timestamp, the call processes only the earlier wakeup and returns, leaving the submitted component edge queued while the outer testbench advances to its next timestamp. Fresh evidence beyond the settle_at fixes is that the nonempty-events branch in testbench.rs still uses a single step; drain internal wakeups through the submitted timestamp before returning from that branch.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
# Conflicts: # crates/celox-backend-x86/src/backend/native/isel/tests/wide.rs # crates/celox-sv-analyzer/src/ast/procedural.rs
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a44e5dc039
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Watchers depend on unpacked arrays too, so `@(a[0])` sees a store and restore of the element within one run. - The waiting processes run between the register updates of a cascade, and after the last one, so a waiter on an expression two cascaded registers change sees the intermediate value (IEEE 1800-2023 4.5). - An event expression may call only functions without effects besides their results: it is evaluated whenever an operand may have changed. - `static` locals, and the lifetime-less locals of static tasks, keep their values between calls; an initializer runs once, before time zero, and one without an explicit lifetime in a static task is rejected (6.21). - The tasks of generate scopes are known by qualified names, and an `always` is classified by the tasks its own scope resolves, from the elaborated generate items. - The event counters of a package variable are the package's: a kernel of any module records the events of its stores there, and a waiter of any module reads them. Such an event is the variable itself. - `Simulation::step` and `run_until` settle the combinational logic a host write left dirty before polling the waiting processes.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 93fb13a13b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 31fae49500
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 09b0bf6bd9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f931d6d5e2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 256d200291
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
This pull request does not currently match the merge queue conditions, so it cannot be queued from here. The box comes back if it matches again. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c35dd0298
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3dfd0becc4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 927ff6435e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c5d190c61
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 70c7bf1f34
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 70c7bf1f34
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ee7e8aaf9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5b11572f1f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5cbe77791d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| match eval(condition) { | ||
| Some(value) => items.push(expression( | ||
| if value != 0 { then_expr } else { else_expr }, |
There was a problem hiding this comment.
Use four-state truth when folding ternary calls
Fresh evidence beyond the fixed statement-level branch folding is a conditional expression such as 4'bx001 ? f() : g(): every caller supplies an integer evaluator based on known_loop_value, so this match returns None even though SystemVerilog truth selects only f(), and the fallback collects side effects from both functions. If the unreachable function performs additional writes to an event-observed value, the pulse summaries can report multiple writes and reject a valid hierarchy; use the existing typed truth evaluator to select the reachable arm before combining call effects.
Useful? React with 👍 / 👎.
| _ => ProceduralFlow { | ||
| fallthrough: stmt_may_fall_through(stmt), | ||
| continues: false, |
There was a problem hiding this comment.
Stop after provably nonterminating loops
Fresh evidence beyond the fixed selected-break suffix is a forever loop with no reachable break: stmt_flow falls through to this default and reports that the loop can continue into the following statement. Consequently, reachability and pulse/dependency summaries visit dead code such as initial begin q = 0; forever #1; q = a; end, potentially recording a nonexistent a -> q dependency and rejecting a parent observer when a has multiple writes, although execution can never reach q = a; classify provably nonterminating loops as non-fallthrough.
Useful? React with 👍 / 👎.
| @@ -2027,11 +2292,251 @@ pub(super) fn stmt_calls( | |||
| } | |||
| _ => {} | |||
There was a problem hiding this comment.
Traverse calls in delay expressions
When a delay operand calls a function with side effects, Stmt::Delay reaches this catch-all and stmt_call_effects records none of the function's writes, even though executable lowering evaluates the call before suspending. For example, a child process executing #pulse_delay() where pulse_delay writes an output high and then low can bypass the cross-instance multiple-write guard; a parent waiting on that output then misses the transient event because the child kernel returns with the original value. Include the delay expression in the call traversal so its writes participate in pulse validation.
Useful? React with 👍 / 👎.
| for (id, _) in &newly_triggered { | ||
| if let Some(event) = self.event_info[*id].eval_ff_event { | ||
| executor.fire_external_event(event, current_time)?; |
There was a problem hiding this comment.
Settle component outputs between replayed occurrences
When one external-component clock domain has multiple replayed occurrences in the same time slot, this loop invokes every component hook and applies each returned write before the single combinational evaluation below. If the component output toggles on each clock, the first write is overwritten by the second before trigger detection or waiter sampling, so a downstream edge-sensitive domain or @(output) process misses the intermediate edge even though both clock occurrences were replayed. Settle or explicitly count each component publication before firing the next occurrence.
Useful? React with 👍 / 👎.
|
Converted to draft: superseded by the redesign in #1123 (comment). Kept as a reference implementation; it will be closed when its replacement merges. |
Part of #1123. SystemVerilog initial and timed always blocks execute as resumable kernels with delays, event/level waits, inactive-before-NBA ordering and a time-slot delta budget. Process loop backedges now charge that budget while immediately resuming the same process; constant-true waits and conditional continues cannot hang inside one invocation. Finite process ordering is preserved, and an interrupted continuation resumes before other waiters are polled. For supported clock/reset blocks, event roles come from their use in the body, so reset-first and clock-first sensitivity lists have the same classification and execution.
Event counters preserve transient stores, repeated occurrences and coincident scheduled/host edges. A single queued drive records its occurrence even when a captured host edge already occupies the domain. Active-region replays evaluate NBA right-hand sides before publishing the shared batch. Hierarchy dependencies, pulse counts, fixed-time proofs and sequence termination share typed constant-branch selection: unreachable reads, function effects and post-break suffixes no longer create false dependencies or writes. Zero-trip bodies and steps are excluded using the same typed entry proof as the write summary, while loop initialization/header effects remain visible. Dynamic/effectful choices remain conservative. Repeated FF evaluations retain distinct pending working images and publish them in evaluation order; transition counters preserve intermediate NBA edges for waiters and cascaded FFs. Ordinary single-occurrence batches copy no images; retained images and the final restore image are bounded to 64 MiB per publication batch, with an explicit runtime error on overflow.
Finish is latched outside the bounded runtime-event ring by every backend writer and the bytecode writer. Diagnostic overflow or draining cannot discard termination; checkpoint/state restoration resets the latch explicitly. Native container18 rejects older code with the previous event-header ABI. Native attachment requires trust in the entire compiler-produced artifact, including code and ABI metadata. State files retain version4 compatibility with versions1–3.
Host writes share a publication helper: eager RuntimeEventDrain settling captures FF edges and waiters even when the simulator was clean before the write. Host settlement probes event and level waits without running continuations, keeping satisfied level waits visible to next_event_time after explicit or eager evaluation. Rust next_event_time exposes unsampled host writes to suspended processes, event domains and finish sites using a conservative current-time marker. Private checkpoints preserve pending work and sampled readiness; restoration dirtiness alone does not invent host work. JavaScript nextEventTime settles shared-memory writes and probes readiness. Finish remains stable across lazy reads, event drains, checkpoints and waveform operations.
Loop reachability distinguishes normal fallthrough and continue from break/return, including selected and dynamic branches. A loop step contributes reads only when control can reach it. While/do-while and wait summaries use configured-state truth, so masked false values preserve fixed write times, masked values containing a known one retain their executed body/delay, and immediately true waits preserve exact child write times in each state mode. Combinational write counts use the same typed branch and sequence-flow analysis as runtime reachability: unconditional loop exits cap body multiplicity at one and exclude unreachable steps, suffixes and post-test conditions; reachable continues retain their step and iteration effects. Hierarchy dependency scans include used default arguments and nested default calls, with call-shape visitation separate from body visitation.
A finished Simulation retains later host stores without implicitly evaluating combinational logic, including when a concurrent runtime-event drain is active. Terminal outputs and diagnostics remain frozen until explicit eval_comb is requested. Finished checkpoint restores also skip eager drain evaluation. Finished state files retain layout-independent matching: available combinational values are restored without evaluation, optional combinational objects may be absent or differently sized, and persistent state must still match.
Repeat counts containing any X/Z bit become zero; known counts retain their original width in the hidden counter, including bits above 64. Negative counts remain zero, count functions evaluate once, and explicit casts control intentional truncation. Runtime lowering and typed loop/write proofs share this rule while preserving evaluation effects and state-mode-dependent known comparisons. Fixed-time delay proofs follow executable X/Z-to-zero, width and signedness rules. Untimed state files continue to use version 1; additional schedule metadata selects the newer formats it requires.
Delay expressions retain their self-determined width through evaluation and X/Z detection, then convert to the 64-bit time value. This also preserves narrow arithmetic overflow and explicit casts.
Validation: runtime41, frontend5, library225, SV2520 (20 existing exclusions), checkpoint30, state file17, concurrent initial/runtime17, native image24, native boundary6, stepping7 and VCD7 pass. Veryl FF/cascade, multi-clock, array and working-snapshot consumers also pass. Failed-before regressions cover omitted-default hierarchy pulse guards, pending combinational finish queries, and overwritten NBA values. Four-backend tests in both state modes verify default overrides/separated writes, pure queries/checkpoint restoration, intermediate NBA edges, independent domains and X/Z masks. Formatting, affected-crate Clippy, a fresh NAPI build, JS436, types and lint pass. Icarus13 validates the timed NBA reproduction; Verilator5.052 loses its intermediate edge, recorded as a discrepancy. The earlier 65-bit repeat boundary also remains a recorded external mismatch. No shared catalogue, exclusion or retained verification baseline changes. Latest-head CI must finish before merge.
The Windows generation-ticket EPERM repair preserves an existing owner's priority during bounded read retries. Its fault-injection/sidecar tests, plugin build and lint remain validated; native Windows and latest-head CI must complete before merge.