axi_demux: enforce exactly MaxTrans in-flight transactions (fixes #249) - #440
Conversation
Document INCR/FIXED/WRAP burst behavior in the module headers of axi_dw_converter, axi_dw_downsizer, and axi_dw_upsizer. Closes pulp-platform#429.
… interfaces. The original multi-dimensional interface module is not supported by many tools. Downstream users can still trivially write their own intf wrapper. Close pulp-platform#353.
…meter (pulp-platform#399) * src: axi_fifo_delay_dyn: Fix incorrect power-of-two check for `Depth` parameter The `axi_fifo_delay_dyn` module's parameter constraint checker incorrectly identified valid `Depth` values as not being a power of two. This commit corrects the logic to accurately verify that the `Depth` parameter is a power of two. * Update src/axi_fifo_delay_dyn.sv --------- Co-authored-by: Chen Wu <chenwu@iis.ee.ethz.ch>
* Bump to common_cells v2 * fix(cc): fix cc_ module parameter names for common_cells v2 Update parameter names to match the actual cc_ module API in v2-test: - cc_delta_counter: Width->WIDTH, StickyOverflow->STICKY_OVERFLOW - cc_stream_register: data_t->T - cc_fifo: FallThrough->FALL_THROUGH, Depth->DEPTH, data_t->dtype - cc_counter: Width->WIDTH Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * hw: Align mux and demux to common_cells v2 * hw: Align params name to common cells v2-test * hw: Remove test_i ports * hw: clean up dead test_i ports and use cc_pkg::lzc_mode_e enum for the cc_lzc MODE parameter. * fixed indentation * bumped common-cells v2.0.0-beta and tech-cells-generic 0.2.14 * bumped common2 fixes for synopsis tools * scripts: add target cc_no_deprecated * deps: Bump `common_cells` to `v2.0.0-beta.2` --------- Co-authored-by: Lorenzo Leone <lleone@iis.ee.ethz.ch> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Chen Wu <chenwu@iis.ee.ethz.ch> Co-authored-by: Niccolò Giuliani <niccolo.giuliani44@gmail.com>
08dbeae to
88939f5
Compare
imchenwu
left a comment
There was a problem hiding this comment.
Hi, thx for working on this. :) As this PR requires exposing a new port, we'll have to merge it in the next major release, so I modified the base branch to devel.
|
|
||
| `include "axi/typedef.svh" | ||
|
|
||
| module tb_axi_demux_maxtrans #( |
There was a problem hiding this comment.
Is this tb necessary? I suggest to add assertions inside the axi_demux_id_counters module instead.
There was a problem hiding this comment.
Replied in the main thread with more detail, but short version: the existing tb configs all use non-power-of-2 MaxTrans, so module assertions alone would never fire in CI — this tb is what actually builds a triggering config. Can add assertions on top or drop the tb, whichever you prefer.
|
Thanks for taking a look! Applied your About the tb — I considered moving the check into assertions in Happy to add the assertions on top if you'd like both, or drop the tb if you feel strongly — just wanted to flag why I kept it for now. |
88939f5 to
dc46d0c
Compare
The per-ID in-flight counters were sized with idx_width(MaxTrans) bits, which can only represent values 0 to MaxTrans-1. As a result: - For power-of-two MaxTrans (including the module default of 8), the counters reported full at MaxTrans-1, silently delivering one less outstanding transaction than configured on both the AR and AW paths as well as the open-W-burst counter. - For other values, the all-ones full condition allowed more than MaxTrans outstanding transactions (e.g. 15 for MaxTrans = 10). Widen the counters to idx_width(MaxTrans + 1) bits and compare against MaxTrans directly instead of the counter's saturation value, so the configured limit is enforced exactly. The comparison uses >= rather than == because a simultaneous push and ATOP injection advances a counter by two. Add a directed regression, tb_axi_demux_maxtrans, which issues back-to-back same-ID reads into a demux whose selected master port withholds all R responses: the number of accepted AR handshakes is exactly the counter limit. Before this change it stalls at 7 of a configured 8; after, at exactly MaxTrans for both power-of-two and other values. Fixes pulp-platform#249
Review feedback: with 2**CounterWidth outstanding transactions the counter wraps and any_outstanding_trx_o would report no outstanding transactions. Include the overflow flag in the occupied computation.
dc46d0c to
5d78989
Compare
|
Hi, I checked the current CI. Actually |
Review feedback: replace the specialized testbench with an elaboration-time assertion. The assertion fails as soon as any instantiation configures a counter width that cannot hold MaxTrans, which covers configurations reached through other DUTs (e.g. tb_axi_dw_upsizer instantiates axi_demux with MaxTrans=4 through axi_dw_upsizer) without a dedicated test.
|
Fair enough, you're right — I'd only checked the top-level tb parameters and missed configs reaching the demux through other DUTs. Swapped the tb for an elaboration-time assertion in |
| // inclusive), so they are sized for `MaxTrans + 1` states. Sizing them with | ||
| // `idx_width(MaxTrans)` lets them saturate at `MaxTrans - 1` when `MaxTrans` is a power of | ||
| // two, silently reducing the configured concurrency by one transaction (issue #249). | ||
| localparam int unsigned IdCounterWidth = cc_pkg::idx_width(MaxTrans + 1); |
There was a problem hiding this comment.
| localparam int unsigned IdCounterWidth = cc_pkg::idx_width(MaxTrans + 1); | |
| localparam int unsigned IdCounterWidth = cc_pkg::cnt_width(MaxTrans); |
There was a problem hiding this comment.
TIL cnt_width exists — that's exactly the right helper here (and kind of poetic that the bug was idx_width being used where cnt_width belonged). Applied.
| // pragma translate_off | ||
| initial begin : validate_params | ||
| counter_holds_maxtrans : assert (2**CounterWidth > MaxTrans) else | ||
| $fatal(1, "CounterWidth (%0d bits, maximum value %0d) cannot represent MaxTrans (%0d): \ | ||
| the counters would report full at %0d in-flight transactions.", | ||
| CounterWidth, 2**CounterWidth - 1, MaxTrans, 2**CounterWidth - 1); | ||
| end | ||
| // pragma translate_on | ||
|
|
There was a problem hiding this comment.
Maybe replace by runtime assertions, see the other comment.
Review feedback: size the counters with cc_pkg::cnt_width, which exists for exactly this purpose, and watch the in-flight limit with the suggested runtime assertion properties (full only at or above MaxTrans, no push at or beyond MaxTrans) alongside the existing underflow check.
A stalled AR remains locked while an ATOP can fill its ID counter. The pending AR must still complete, so pushing at MaxTrans is valid in this case.
Summary
The demux's per-ID in-flight counters are sized with
idx_width(MaxTrans)bits — enough to indexMaxTransvalues (0..MaxTrans-1), not enough to count toMaxTrans. Consequently:MaxTrans— including the module default of 8 — the counters report full atMaxTrans - 1: a demux configured for 8 outstanding transactions accepts only 7, on the AR path, the AW path, and the open-W-burst (w_open) ceiling.MaxTrans = 10).This is exactly the behavior diagnosed by the reporter of #249 in 2022; this PR implements the fix (with exact-limit semantics) and adds the regression that was missing.
Fix
axi_demux_simple: widenIdCounterWidthtoidx_width(MaxTrans + 1); gatew_openwith< MaxTransinstead of!= all-ones; passMaxTransto the ID counters.axi_demux_id_counters: newMaxTransparameter (defaults to the legacy saturation value, so standalone instantiations are unaffected); full condition comparesin_flight >= MaxTransinstead of&in_flight.>=rather than==because a simultaneous push + ATOP injection advances a counter by 2.Note on semantics: this makes
MaxTransan exact limit. Non-power-of-two configurations previously enjoyed slack up to the counter's all-ones value (e.g. 15 forMaxTrans=10); they are now limited to exactlyMaxTrans. This matches the parameter's documentation (see also #336).Verification
New directed test
tb_axi_demux_maxtrans: back-to-back same-ID reads into a demux whose selected master port accepts every AR but withholds all R responses, so the in-flight count can only grow; the number of accepted AR handshakes equals the true counter limit.MaxTrans = 8MaxTrans = 10Full
tb_axi_xbarregression (Verilator): 8072 checks, 0 failures, in both the default (10/6) and an all-power-of-two (8/8)MaxMstTrans/MaxSlvTransconfiguration.No existing test could observe this bug: the shipped testbenches all use non-power-of-two limits, and none measures achieved concurrency — the new directed test closes that gap.
Fixes #249