Conversation
The downsizer emitted TotalSubTransfers sub-transfers for every input beat regardless of TKEEP, so the lanes a partial beat marks invalid were pushed downstream as real data. Reported in pulp-platform/pulp-ethernet#5: a 52-byte Ethernet payload produced an 84-byte frame instead of 78. The excess of exactly six is the invalid lanes of the final 64-bit beat, 8 - 2 valid bytes. That design does not connect TKEEP or TSTRB onward to the MAC, so the null lanes reached the wire. The last sub-transfer of a beat is now the index of its highest asserted TKEEP bit, latched when the beat is accepted. It cannot be derived from tkeep_received_q, which is shifted right on every sub-transfer: the target index would shrink as the counter climbs and a full beat would end early. A beat whose only valid byte is lane 0 has no DataOut phase, since that byte is itself the last sub-transfer and must carry TLAST. A beat with TKEEP all-zero still yields one sub-transfer, so it is consumed rather than stalling the stream. Trailing invalid lanes are dropped; non-contiguous null lanes in the middle of a beat are not compacted. Also read tstrb_received_q, not tstrb_received_d, when shifting TSTRB. The two neighbouring lines use _q; this one aliased the next-state variable and only matched because of the default assignment above it. Adds a self-contained testbench stating exact byte counts, including a full-beat case that passes both before and after, so the change is shown not to alter fully valid beats. Against the unfixed RTL four of its ten checks fail. Verified with Verilator 5.006; CI does not run simulation.
dngr2
force-pushed
the
fix/dw-downsizer-honour-tkeep
branch
from
August 16, 2026 02:47
ed8b6b2 to
c57863b
Compare
Author
|
Note on the force-push you will see on this branch: the commit author email was wrong, and I corrected it. The tree is unchanged — same diff, same tests, only the author metadata differs. I know |
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.
The bug
axi_stream_dw_downsizeremitsTotalSubTransferssub-transfers for every input beat regardless ofTKEEP, so the lanes a partial beat marks invalid are pushed downstream as real data.Surfaced as pulp-platform/pulp-ethernet#5: a 52-byte Ethernet payload produced an 84-byte frame instead of 78. The excess of exactly six is the invalid lanes of the final 64-bit beat (
8 − 2valid bytes).pulp-ethernetinstantiates this module to go 64→8 for the MAC (eth_top.sv:123) and does not connectTKEEP/TSTRBonward (framing_top.sv:214-218), so the null lanes reach the wire.Reproduced in Verilator against the unmodified module — a single beat with
TKEEP=0x03,TLAST=1:The change
The last sub-transfer of a beat is now the index of its highest asserted
TKEEPbit, latched when the beat is accepted.It cannot be derived from
tkeep_received_q— that register is shifted right on every sub-transfer, so the target index would shrink as the counter climbs and a full beat would terminate early. I made exactly that mistake first; a full0xFFbeat emitted 5 bytes instead of 8 and hung the testbench. Hence the latch, and hence the full-beat check below.Two edge cases:
DataOutphase — that byte is itself the last sub-transfer and must carryTLAST.TKEEPall-zero still yields one sub-transfer, so it is consumed rather than stalling the stream.Scope: trailing invalid lanes are dropped. Non-contiguous null lanes in the middle of a beat are not compacted — that needs real compaction logic and a wider behavioural decision, so I left it out rather than half-doing it.
Also in this commit
tstrb_received_d = tstrb_received_d >> StrbWidthOutread the next-state variable where both neighbouring lines use_q. It happens to produce the right value today only because of the default assignment above it. Changed to_qfor consistency.Testing
New self-contained testbench,
test/tb_axi_stream_dw_downsizer_tkeep.sv, registered inBender.yml. It states exact byte counts rather than using the randomized drivers, so the checks read as the specification.TKEEP=0x03TKEEP=0xFFTKEEP=0x7FFour of the ten checks fail against the unfixed RTL, so they are load-bearing. The full-beat case passes both before and after — that is the one showing fully valid beats are unchanged.
Verified with Verilator 5.006. I note that CI runs license, commit and verible lint but no simulation, so these results are from a local run rather than from the pipeline — worth an independent check on your side. I did not modify the existing
tb_axi_stream_dw_downsizer, which uses the randomized driver framework and cannot easily express a specificTKEEPpattern.Unrelated observation
pulp-ethernetpins this package at472751f550e3918215603e21734fe0ece3c66f79in itsBender.lock, and that revision is not reachable in this repository — I fetched all refs. So that consumer currently pins a commit nobody can fetch, and this fix will not reach it until the pin moves. Flagging it here since it affects whether the fix actually lands for the reporter; happy to raise it separately.