Repository navigation
Implement Zawrs and wait for wfi, wrs.nto and wrs.sto in one place - #1894
Closed
davidharrishmc wants to merge 9 commits into
Closed
davidharrishmc wants to merge 9 commits into
davidharrishmc wants to merge 9 commits into
Conversation
wrs.nto and wrs.sto wait on the reservation set. Wally has a single hart, so no other agent can write the reservation set and only an interrupt or the timeout can end the wait, which makes both instructions behave like wfi. They therefore reuse the wfi stall path, the wfi interrupt delay, and the wfi timeout counter, so the only new state is a pair of decoders. The counter now clears whenever no wfi or wrs is waiting and saturates at the threshold, rather than clearing only on a trap. wfi relied on its timeout always causing a trap to clear the counter, but a wrs timeout retires normally, so the counter has to clear itself. On timeout, wrs.nto raises an illegal instruction below M mode when mstatus.TW is set, matching wfi. Unlike wfi it does not trap in U mode when TW is clear, and wrs.sto never traps; both simply complete. The reservation set is not consulted, which the specification permits since an implementation may end the stall for any reason. Hypervisor support and hstatus.VTW are out of scope. Enabled on rv64gc only, gated by ZAWRS_SUPPORTED everywhere else. Verified with the ZawrsSm, ZawrsS, and ZawrsU arch-test suites on rv64gc. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Shorten the wfi timeout from 2^16 to 2^14 cycles on every configuration, and give the Zawrs instructions their own thresholds: 2^13 for wrs.nto and 2^12 for wrs.sto. One counter still serves all three; each waiting instruction taps its own bit, so the only cost is a two-input mux that collapses away when Zawrs is disabled. WAIT_TIMEOUT_BIT sizes the counter to the largest threshold in use, and ignores the wrs thresholds when Zawrs is disabled so those configurations keep the same flops. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
davidharrishmc
force-pushed
the
dh/zawrs
branch
from
September 18, 2026 18:13
bad50da to
59a2366
Compare
The specification allows the hart to stall only while the reservation set is valid, so a wrs with no reservation has to complete rather than waiting out its timeout. Export the committed reservation state from lrsc up through atomic and lsu to privdec, and require it before wrs waits. Timing: ReservationValidW is the right signal to sample. The lr that sets it is in W when the wrs reaches M, so it is already updated. It then holds for the whole wait, because a wrs in M is not a memory operation and a wait stall does not assert StallW, which is what gates the flop. The timeout counter still keys off wrsM rather than the gated wait signal. Keying it off the gated signal would clear the counter as soon as the timeout fired, re-arming the wait and livelocking. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
wrs.nto has no timeout: only an interrupt, an invalidated reservation, or the mstatus.TW illegal instruction below M mode ends it, so like wfi it waits indefinitely otherwise. wrs.sto keeps completing when its timeout expires. Completing wrs.nto on timeout was only there to keep a wrs with no reservation from hanging, which the reservation check now handles properly. WRSNTO_TIMEOUT_BIT still sets the bounded time limit after which mstatus.TW turns the wait into an illegal instruction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
privdec is instantiated only when Zicsr is supported, and that is the first term selecting the controller's exact decode of the privileged fields, so PrivilegedM already requires funct3 = 0 and rd = 0. The rdzeroM terms on sinval.vma, sfence.w.inval, sfence.inval.ir, and sfence.vma were therefore redundant, and rdzeroM itself is now unused. An encoding probe confirms the behavior is unchanged: the four well-formed fence encodings still execute and all four with rd = x1 still raise illegal instruction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Oct 5, 2026
Open
…t redesign upstream/main has since reverted Zimop, Zcmop and Zabha; the conflicts keep main's side and take only the Zawrs lines. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: David Harris <David_Harris@hmc.edu>
A waiting wfi or wrs now stalls the whole pipeline through StallW (WaitM), like an LSU stall, instead of stalling M and flushing W. One flop (WaitedM) records that the instruction in M has waited, and one counter of waiting cycles, held while the instruction stays in M and cleared when M advances, provides the mstatus.TW limit (wfi, wrs.nto) and the wrs.sto short timeout. This replaces WFIStallM, WFIInterruptedM, StallMCause, LatestUnstalledW, wfiW and the wfiM | wfiW interrupt gate, and fixes: - the instruction after a woken wfi used a stale operand, because W was flushed every waiting cycle and forwarding stopped (openhwfoundation#1933); - an interrupt already enabled and pending when a wfi executed, e.g. just enabled by a CSR write or xRET, was taken after the wfi retired; it is now taken on the wfi (openhwfoundation#1935). A wfi or wrs woken by an interrupt still retires and the interrupt is taken with mepc = pc + 4; - a trapping wfi both retired and trapped (FlushWCause = TrapM, openhwfoundation#1926); - the next instruction took a spurious TW trap when a wfi woke on the cycle its count reached the limit (openhwfoundation#1923), and the count no longer depends on TrapM, so it cannot change while a trap waits for StallW (openhwfoundation#1930); - a TW timeout coinciding with an enabled interrupt wrote mcause = 5 without the interrupt bit: WaitedM gates ValidIntsM, so CauseM agrees. wrs.nto now shares the TW limit with wfi (WRSNTO_TIMEOUT_BIT and WAIT_TIMEOUT_BIT are removed); the counter is sized in privdec. Tests: wfitimeoutnext, wfiBackToBack, wfiForward and csrwfiInt from openhwfoundation#1923/openhwfoundation#1926/openhwfoundation#1933/openhwfoundation#1935, plus wfitimeoutint (TW timeout racing an enabled interrupt), wfiTW (TW wait woken before the limit, timeout not retired, U mode) and wrsWait (Zawrs wake, timeout and forwarding cases). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: David Harris <David_Harris@hmc.edu>
…ckstep Bring back openhwfoundation#1894's WRSNTO_TIMEOUT_BIT and derived WAIT_TIMEOUT_BIT, so wfi taps WFI_TIMEOUT_BIT, wrs.nto taps WRSNTO_TIMEOUT_BIT and wrs.sto taps WRSSTO_TIMEOUT_BIT on the one wait counter, sized by WAIT_TIMEOUT_BIT. The configuration files are again identical to openhwfoundation#1894. Waive wfiTW, wfitimeoutint and wfitimeoutnext in lockstep: ImperasDV traps a wfi below M mode with mstatus.TW = 1 at once, while Wally waits a bounded time, and both are legal (mstatus_tw_always_illegal, mstatus_tw_op). Replace the stale wfiW, WFIStallM and WFITimeoutM names in the FPGA debug lists and wave.do. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: David Harris <David_Harris@hmc.edu>
davidharrishmc
marked this pull request as ready for review
October 6, 2026 22:10
This was referenced Oct 6, 2026
…enhwfoundation#1932) into the wait redesign Resolve hazard.sv and wave.do in favor of the unified wait (WaitM), which already has openhwfoundation#1926's FlushWCause = TrapM, and drop the duplicate wfiBackToBack entry in coverage64gc. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: David Harris <David_Harris@hmc.edu>
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the Zawrs wait-on-reservation-set instructions,
wrs.ntoandwrs.sto, enabled onrv64gcand gated byZAWRS_SUPPORTEDelsewhere. It also rebuilds the wfi wait so that wfi,wrs.ntoandwrs.stoshare one wait mechanism. This supersedes #1923, #1933 and #1935 and carries their tests. #1926, now merged, is kept:FlushWCause = TrapM.Wait design
A waiting instruction stays in M.
WaitMstalls the whole pipeline throughStallW, as an LSU stall does, so the instruction in W keeps forwarding. One flop,WaitedM, records that the instruction in M has waited, and one counter of waiting cycles sets the time limits. The counter holds while the instruction stays in M and clears when M advances.StallWCause |= WaitM & ~FlushWCause,FlushWCause = TrapM,StallM = StallWValidIntsM = (Committed | WaitedM) ? 0 : EnabledIntsM. InterruptM no longer gates on wfi.WFIStallM,WFIInterruptedM,StallMCause,LatestUnstalledW,wfiWand the~wfiM | wfiWinterrupt gate.TW= 1, or U mode with S: illegal instruction after 2^WFI_TIMEOUT_BITcycles, mepc = the wfi, not retiredTW= 1: illegal instruction after 2^WRSNTO_TIMEOUT_BIT; otherwise waitsWRSSTO_TIMEOUT_BITThe limits are 2^14, 2^13 and 2^12 cycles on every configuration. The counter is sized by
WAIT_TIMEOUT_BIT, the largest limit in use.With a single hart, no other agent can write the reservation set. Once a
wrsholds a reservation, only an interrupt or a timeout ends the wait. The committedReservationValidWis exported fromlrsc.sv. Hypervisor support andhstatus.VTWare out of scope.Bugs fixed
li a0,42; wfi; addi a1,a0,0gave the old a0. The same happens to anlrresult after awrs.intr_mip_mie_xret_csrwrrequires.TrapM, so it cannot change while a trap waits for~StallW.Also in this PR
PrivilegedMalready requiresfunct3 = 0andrd = 0, so the redundantrdzeroMterms on the fence encodings are dropped. The illegal encodings still trap.Testing
New self-checking tests in
tests/coverage, all listed incoverage64gc:wfitimeoutnext,wfiBackToBack,wfiForward,csrwfiInt.wfitimeoutint: a TW timeout racing an enabled interrupt.wfiTW: a TW wait woken before the limit; a timed-out wfi that does not retire; U mode.wrsWait: no reservation, the short timeout, the TW limit, U mode withTW= 0, an interrupt already pending, and forwarding across the wait.ACT
privsuites (Zawrs, Interrupts, Sm, S, U, Ssstrict, Zicntr, Exceptions) were built with Zawrs enabled and all pass:ImperasDV lockstep:
wrsWait,wfiBackToBack,wfiForward,csrwfiIntandwfitimeout.wfiTW,wfitimeoutintandwfitimeoutnextare waived inregression-wally. ImperasDV traps aTW= 1 wfi below M at once, while Wally waits a bounded time. Both are legal:mstatus_tw_always_illegalallows the first andmstatus_tw_opthe second.lint-wallyis clean, and buildroot Linux boots to the login prompt.Synthesis, sky130 rv64gc full core at 200 MHz, compared with the Zawrs-only version:
Note for the reviewer
The ACT test-generation config for
cvw-rv64gcmust declare Zawrs, or theSsstrictillegal-encoding sweep expectswrs.ntoandwrs.stoto trap. Two files need changing:Zawrsand setZAWRS_NTO_IS_NOP: falsesail.json: setZawrs.supported: trueSupersedes #1923, #1933 and #1935.
🤖 Generated with Claude Code