The closed WDFCVBI2.COD driver's short-name generator can assign the
same 8.3 name to two different long-name directory entries, corrupting
the FAT directory structure (confirmed live on hardware via chkdsk:
2026_09_01 and 2026_0~1.--0 are the same day, split across two colliding
entries). Since the driver ships as a binary with no source, documented
the issue in README and started writing an open replacement SD/FAT32
driver from scratch.
This commit adds the in-progress diagnostic scaffolding for that new
driver (test_sd_raw/test_sd_raw2 in zifi.asm, marked with ;DIAG:
comments): a standalone SD-card SPI implementation (ports CONF=#77/
DATA=#57) that inits the card, reads sectors via CMD18+CMD12, and
parses the FAT32 boot sector/root directory independently of the
closed driver. Still under active debugging - the command handshake
(R1/token) checks out correct but the bulk data payload comes back
wrong, root cause not yet found. Not wired into the real boot path
beyond the diagnostic hook, and not ready to replace the closed driver.
FILE_NAME is a fixed 48-byte buffer, but the loop copying the
filename parsed from the download URL had no length check, so a
filename longer than 48 characters would overflow into adjacent
variables (FILE_INI, DIR_zifi, DIR_download, DIR_date). Bound the
copy loop to 48 bytes.
Verified on hardware via a temporary diagnostic test (since removed):
folder/file creation with long names and write+read-back through the
FAT32 driver both work correctly, and downloads/<date> is confirmed
write-only (playback/viewing always reads from memory, never disk).
Documented the fix in README.md.
zifi_input_fifo_check now tracks inactivity in frame-counted quanta
(~5s @ 50Hz, so independent of CPU/turbo clock): after ~10s of total
silence from the server on a request, it's retried automatically (up
to 3 times, resending the already-built request). If retries are also
exhausted: for a music download, skip to the next track in the list
(capped at 8 consecutive dead tracks so an unreachable network doesn't
spin through the whole playlist forever); for anything else, fall back
to the existing manual-cancel path.
Confirmed working on hardware.
Uncommenting it in int_text_on didn't fix the mouse cursor clipping
above the bottom panel (confirmed on hardware), and it was commented
out in the original code for presumably a good reason. Not worth
carrying an unexplained hardware-register change with zero upside.
Bottom control panel sat a couple pixels too low relative to the top
panel (pre-existing, not a session regression) - nudged GYOFFSL in
int_text_off from 47+240-1 to 47+240. Confirmed correct on hardware.
Also uncommented the TSU_SEN write in int_text_on so hardware sprites
(mouse cursor) are enabled during text mode too, not just graphics
mode. Doesn't fix the known cursor clip right above the bottom panel
(that appears tied to a fixed screen row, independent of panel
position or this bit - left as a known issue, documented in README).
show_now_play_link (blinking highlight for the currently playing track
in the list, plus the end-of-track autoplay/parse_url check) still ran
inside int_text_off via pt_play, doing its own extra page switch
(set_Textpage_lite) and an 80-byte write - on top of the analyzer this
was the remaining source of the vertical stripe flicker, specifically
when the playing track is scrolled into view. Split it out of pt_play
and call it from the main loop alongside the analyzer; the player tick
itself is untouched.
Confirmed on hardware: no flicker left, including across autoplay to
the next track.
The AY volume-bar indicator (music_analizator) ran inside int_text_off,
the same precisely-timed interrupt chain that switches between text and
graphics video modes. Its DMA clear + page switching + drawing could
overrun that timing budget on dynamic tracks, causing visible vertical
stripe flicker. Moved it to the main loop (once per frame, after
wait_frame) instead, leaving the player tick (pt_play) and its tempo
timing untouched inside the interrupt.
Also waits for the DMA clear to finish before drawing bars into the
same memory (previously a write race).