frontend: Eliminate external_pending launch deadlock (non-external next_id via rd_swacc)#147
frontend: Eliminate external_pending launch deadlock (non-external next_id via rd_swacc)#147DanielKellerM wants to merge 1 commit into
Conversation
…ernal status/done_id Removes the peakrdl external_pending whole-block stall that #134's rd_ack gating deadlocks against. next_id becomes a normal internal register with a rd_swacc read-strobe (declared as a UDP) driving the launch, matching the old reggen hwext+hwre behaviour: no external register, no cpuif_req_stall, one-cycle read. Combined with the native-APB frontend (#131) and internal status/done_id (#135).
SW C-header note (for downstream consumers)Since this migrates the reg frontend fully to SystemRDL, downstream SW that consumed the old reggen
Flagging per @-review discussion: it may be worth having iDMA itself ship a |
|
Superseded by #153 (frontend/reg-deadlock-fix): a minimal, template-only fix that keeps next_id external and preserves the canonical BLOCKING launch contract, fixing the external_pending deadlock at the rd_ack driver with a pending latch — plus the first directed reg-frontend testbench proving it (non-vacuous: the watchdog fires on the unfixed template). This #147 approach (non-external next_id + rd_swacc) changed the contract to poll-based, could drop a launch under contention, and was untested. Closing in favor of #153. |
Problem
Reading
next_idlaunches a DMA. Since #73 the register frontend modelsnext_id/status/done_idas PeakRDLexternalregisters. peakrdl-regblock emits anexternal_pendinglatch drivingcpuif_req_stall_rd/wr— a whole register-block stall while any external access is outstanding.#134 then gated the external
rd_ackon the decodedreqstrobe. Butexternal_pendingmaskscpuif_req, soreqis high for only one cycle; onceexternal_pendinglatches,reqdrops to 0. If the arbiter grant (arb_ready) is not high in that first cycle,rd_ack = req & arb_readycan never fire again →external_pendingis stuck high → the whole reg block is frozen. When the config port shares interconnect ordering with other traffic (e.g. a mem-tile DMA whose config slave shares a demux/NoC path with CPU stores), this frozen block back-pressures and deadlocks unrelated memory traffic.The pre-0.7.0 (reggen) frontend never had this:
next_idwashwext + hwre(a hardware-external register with a.reread strobe) — noexternal_pending, no whole-block stall; the read stalled only locally via the wrapper's reg-busready.Fix
Model the observation registers as non-
external, reproducing the reggen behaviour in PeakRDL:next_id: a normal internal register (sw=r; hw=w) with ard_swaccread-strobe (declared as a UDP) driving the launch — a combinational one-cycle pulse, exactly like the old.re.status/done_id: internal (from frontend: Model status/done_id as internal status registers #135).With no
externalregister, peakrdl emitsexternal_pending = 0and hardwirescpuif_req_stall = '0— no whole-block stall, no deadlock, and noassert_bad_ext_rd_ack. The frontend fires the launch offrd_swacc; no ack handshake, no hold latch.Relation to other PRs
This branch incorporates:
status/done_id) — required, since all observation regs must be non-external to fully removeexternal_pending.and fixes #134's launch-read deadlock via the
next_id→rd_swaccchange.Suggested merge order: #131 → #135 → this. It can also be merged standalone (it contains all three); if #131/#135 land first, this rebases down to just the
next_id→rd_swaccchange + therd_swaccUDP declaration.Test
Validated on a Gwaihir mem-tile DMA (l2_dma L2↔L2 passthrough), where the config port shares the mem-tile demux/NoC path with CVA6 SPM stores. On
devel+ #134 this hard-deadlocks the SoC; with this fix it runs to completion (SLINK SUCCESS), matching the 0.6.5 baseline, with zero assertions.