Skip to content

[dv] Wait for helpers before ending run_phase - #2511

Open
kulan-pal wants to merge 1 commit into
lowRISC:masterfrom
kulan-pal:dv/tb-teardown-noa
Open

kulan-pal wants to merge 1 commit into
lowRISC:masterfrom
kulan-pal:dv/tb-teardown-noa

Conversation

@kulan-pal

@kulan-pal kulan-pal commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

When a helper is still waiting at test end, a test that already logged payload=TEST_PASS can fail with:

Error-[NOA] Null object access

Helpers such as wait_for_csr_write raise an objection while they wait for an event. The base test
clears cur_run_phase when wait_for_test_done() returns, even if a helper is still waiting. That helper keeps
the phase open, and when its event arrives, its drop dereferences null. We saw this downstream in debug and
interrupt tests, at roughly 1 in 1000 runs.

Events still arrive after test end because the core keeps running. vseq.stop() does not stop
fetch_enable_seq, which turns fetch back on. The riscv-dv program then runs its end-of-test trap handler, which
writes more signatures.

run_phase now keeps cur_run_phase until no helper objection is left. A helper whose event never comes still
fails on its own timeout, as on master. Helpers that start after that point, and the directed-test cleanup, leave
cur_run_phase alone.

The directed cleanup is otherwise unchanged. It still kills check_stimulus() at test end and drops one
objection. A stuck directed check is therefore discarded, and two stuck at once leave an objection until the test
timeout, as on master.

Tested on VCS U-2023.03-SP2 with the opentitan config, same programs and seeds on both sides. Local canaries
(not in this PR) use the real helpers and teardown. They cover late and missing events, the clock edge where the
handle is nulled, a helper that starts after that, and directed cancellation. The ones that inject an event
disable fetch_enable_seq, so no program signature write lands between the injected words.

Check master 4dd3932a this PR
Helper event arrives after the null, seeds 1-4 4/4 Error-[NOA] at the helper's drop 4/4 pass, the helper gets its event
Helper event never comes (a CSR write, a dret), 2 seeds each 4/4 fail on the helper timeout same
Program that passes without the setup handshake fails on the MSTATUS timeout same
Helper event one clock before, on, and one clock after the null, 2 seeds each before passes; on and after Error-[NOA] 6/6 pass
Helper that starts after the null Error-[NOA] at its raise passes, the helper gets its event
Two directed checks stuck at test end test timeout same
Arithmetic, debug and interrupt tests (7), seeds 1-2 14/14 14/14
riscv_reset_test, seeds 2-5 4/4 4/4
Memory error, PMP, nested IRQ, reset and assorted-traps tests, seed 1 5/6 5/6, same assorted_traps mid-test cosim mismatch

No dependencies. #2444 adds a copy of this run_phase in core_ibex_elf_manifest_test.sv, which would need the
same change.

AI disclosure (CLA §9): written with help from Claude Code and reviewed with OpenAI Codex; I have reviewed and understood every change and take full responsibility for it.

@h-filali h-filali left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kulan-pal for this PR.

I have a couple of general questions.

Do you know why these helpers are still running at the end of the test? cur_run_phase is only nulled after wait_for_test_done() returns. By then fetch_enable has been off for about 3000 cycles, and with it off the core neither fetches nor executes.

What happens if a helper hangs because of an RTL bug, for example a dret that never comes shortly before the end of the test? As I read the change, that objection is reclaimed with a UVM_LOW info line and the test passes.

A helper still waiting at test end keeps its objection. When its event
comes, it drops it through the nulled cur_run_phase, and a test that
already passed fails with a null object access.

Keep cur_run_phase until no helper objection is left. A helper whose
event never comes still fails on its own timeout. Helpers that start
after that point, and the directed-test cleanup, leave it alone.

Signed-off-by: Kulan Palanichamy <kulan.palanichamy@opentitan.org>
@kulan-pal kulan-pal changed the title [dv] Reclaim helper objections at run_phase end [dv] Wait for helpers before ending run_phase Sep 29, 2026
@kulan-pal

Copy link
Copy Markdown
Contributor Author

Thanks, both good questions.

Why helpers are still running. The core keeps running after test end. vseq.stop() does not stop
fetch_enable_seq, so fetch comes back on, and the riscv-dv end-of-test trap handler writes more signatures. With
+disable_fetch_enable_seq=1, the same local programs stop within a few cycles of TEST_PASS. With it on, they keep
executing until the phase ends. The IRQ and debug loops don't check test_done, so a helper can still be waiting.
If its event comes after cur_run_phase is nulled, its drop hits null.

A helper that hangs. You're right, the previous version turned that timeout into a pass. Now a helper that
is still waiting keeps cur_run_phase valid. If its event never comes, it fails on its own timeout, as on master.
I checked that with local tests where a CSR write or a dret never arrives. The directed tests' cleanup is
unchanged: it still cancels check_stimulus() at test end and drops one objection. I've left that alone here.

@bonnie-banks123

Copy link
Copy Markdown

The latest revision looks correct: it keeps the phase handle until the outstanding helpers finish, so they can drop their objections without dereferencing a null handle. I didn’t find an issue with the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants