Files
vt1200/harness/udpstream
arti 9af7b4fb8d fix(rx): release descriptors individually instead of flipping the whole ring
The receive loop re-armed all 16 descriptors into the other slot after every
completed frame.  During a burst that re-pointed descriptors the chip had
ALREADY filled but the consumer had not read, so those frames were lost without
a trace: the LANCE DMA log shows all 23 dictionary datagrams written by the
chip, 1.132 ms apart (the MTU/bandwidth poll cadence), while the payload's own
counters accounted for 4 (DICT_BYTES=1448, dict_bad=3).  Nothing was dropped by
MAME; the ring was being rewritten under the frames it held.

rx_switch()/rx_armed are gone.  A descriptor is held (rx_hold) while its
datagram belongs to the frame being assembled, and rx_release() hands each one
back -- into the other slot -- only once that frame has been parsed or
abandoned.  Nothing the chip delivered is ever re-pointed unread.

Measured, same zero-gap 23-datagram dictionary upload:
  before                      dgram=4   DICT_BYTES=1448   dict_bad=3
  release fix, 16 descriptors dgram=18  DICT_BYTES=24616  dict_bad=0
  plus a 32-descriptor ring   dgram=23  DICT_BYTES=32768  dict_bad=0

The ring is now 32 descriptors because 23 datagrams is the burst the protocol
actually defines (a whole 32 KB dictionary at MAX_BODY 1448), and 16 could not
hold it while the consumer copied.  SLOT_BYTES grows to 49152 to hold the ring;
POOL_BYTES does NOT grow -- the 160 KB "framebuffer reserve" was unused slack
(the decoder paints straight from the fragments), so the extra 24,576 B per slot
comes out of it and the LANCE block keeps its fixed 0x3C000 tail.

RX_OK is now published after rx_release(), not inside the dispatch.  It is the
"frame done" signal a reader polls, and it used to become visible while
descriptors were still being rewritten: ring mode caught a descriptor holding
slot B's high byte with slot A's low word.  A reader that sees RX_OK move now
sees a painted picture and a consistent ring.

vidstream.lua's ring mode follows: it asserts the invariant that replaced the
flip -- the consumed descriptors move to the other slot, the untouched ones stay
-- instead of "all 16 in slot B".

Evidence: 146 unit tests pass; modes rx, draw, ring, tiles, delta and replay all
PASS with their pixel checkers (draw 1024/1024 rows, tiles and replay via
tile_check).  End to end over rdebug with the STOCK sender (no pacing): the
dictionary burst completes (DICT_READY=1, DICT_BYTES=32768, dict_bad=0) and
RX_OK=100 frames paint, TILES_DROP=0.
2026-10-31 19:45:34 +02:00
..