Document FAT32 short-name collision bug in README; add raw SD driver diagnostics
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.
This commit is contained in:
@@ -51,6 +51,8 @@ AT+CIPSNTPTIME? — получить текущее врем
|
|||||||
- теперь DMA-очистка под индикатор громкости дожидается завершения перед тем, как CPU начинает рисовать поверх той же области (была гонка записи);
|
- теперь DMA-очистка под индикатор громкости дожидается завершения перед тем, как CPU начинает рисовать поверх той же области (была гонка записи);
|
||||||
- исправил переполнение буфера имени файла (`create_filename`): при скачивании имя файла из ссылки копировалось в 48-байтный буфер без проверки длины, и если оно было длиннее — переполнение затирало соседние переменные (`zifi.ini`, имена служебных папок) прямо в памяти. Теперь копирование корректно обрезается на 48 символах. Проверено на железе: создание папки и файла с длинными именами (в т.ч. ровно 48 символов) и последующее чтение содержимого — всё работает штатно, никакой драйверной обрезки до 8 символов нет.
|
- исправил переполнение буфера имени файла (`create_filename`): при скачивании имя файла из ссылки копировалось в 48-байтный буфер без проверки длины, и если оно было длиннее — переполнение затирало соседние переменные (`zifi.ini`, имена служебных папок) прямо в памяти. Теперь копирование корректно обрезается на 48 символах. Проверено на железе: создание папки и файла с длинными именами (в т.ч. ровно 48 символов) и последующее чтение содержимого — всё работает штатно, никакой драйверной обрезки до 8 символов нет.
|
||||||
|
|
||||||
|
**Известная серьёзная проблема (пока не исправлена): порча имён папок на FAT32.** Штатный драйвер SD-карты (`_sd/WDFCVBI2.COD`, закрытый бинарник без исходников, автор — "Hacker VBI") при создании папки/файла с длинным именем иногда генерирует короткое имя 8.3, совпадающее с уже существующей записью в каталоге — получаются две разные папки с одинаковым коротким именем на диске. Windows chkdsk потом это обнаруживает и переименовывает вторую запись в `<имя>.--N`, а по факту это два разных физических каталога, которые должны были быть одним (например, файлы за один день оказываются раскиданы между `2026_09_01` и `2026_0~1.--0`). Нашёл и подтвердил дизассемблированием конкретный баг в алгоритме генерации числового суффикса `~N` внутри драйвера, но исправить сам драйвер нельзя — исходников нет, только бинарник. Сейчас пишу отдельный, открытый SD/FAT32-драйвер на замену (реализует только те ~15 функций, которые реально использует ZiFi) — работа в процессе, ещё не готово к использованию.
|
||||||
|
|
||||||
**Известная нерешённая мелочь:** курсор мыши (аппаратный спрайт TSU) обрывается по фиксированной строке экрана прямо над нижней панелью управления — похоже на границу, завязанную на тайминг переключения видеорежима или на аппаратный бордюр, а не на что-то, что двигается вместе с содержимым панели. Я не нашёл способ поправить это без риска сломать что-то ещё, оставил как есть.
|
**Известная нерешённая мелочь:** курсор мыши (аппаратный спрайт TSU) обрывается по фиксированной строке экрана прямо над нижней панелью управления — похоже на границу, завязанную на тайминг переключения видеорежима или на аппаратный бордюр, а не на что-то, что двигается вместе с содержимым панели. Я не нашёл способ поправить это без риска сломать что-то ещё, оставил как есть.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -61,6 +61,8 @@ start
|
|||||||
ld (#beff),hl
|
ld (#beff),hl
|
||||||
call gfx_init
|
call gfx_init
|
||||||
call set_text_colors
|
call set_text_colors
|
||||||
|
call test_sd_raw ;DIAG: standalone SD read test, remove once verified
|
||||||
|
call test_sd_raw2 ;DIAG: standalone SD FAT32 file read test, remove once verified
|
||||||
call load_ini
|
call load_ini
|
||||||
IF cable_zifi
|
IF cable_zifi
|
||||||
call psb_start
|
call psb_start
|
||||||
@@ -3789,6 +3791,795 @@ parsed_link ds #080
|
|||||||
modem_command ds 256+128
|
modem_command ds 256+128
|
||||||
current_paging_url ds 150
|
current_paging_url ds 150
|
||||||
|
|
||||||
|
;DIAG: standalone raw SD-card hardware test - bypasses WDFCVBI2 entirely,
|
||||||
|
;DIAG: talks to the SD controller directly via ports CONF=#77/DATA=#57.
|
||||||
|
;DIAG: Goal: verify our own init+read code can talk to the hardware at all,
|
||||||
|
;DIAG: before writing more of a replacement driver. Reads LBA 0 and checks
|
||||||
|
;DIAG: for the standard 55 AA boot-sector signature. Remove after testing.
|
||||||
|
test_sd_raw
|
||||||
|
call set_Textpage
|
||||||
|
;DIAG: pre-fill the buffer with a recognizable marker before touching
|
||||||
|
;DIAG: the card at all -- if this marker survives a "successful" read,
|
||||||
|
;DIAG: the read loop isn't actually writing to sdraw_buf
|
||||||
|
ld hl,sdraw_buf
|
||||||
|
ld de,sdraw_buf+1
|
||||||
|
ld (hl),#ee
|
||||||
|
ld bc,511
|
||||||
|
ldir
|
||||||
|
|
||||||
|
ld a,%00000001
|
||||||
|
ld (sdraw_csl_val),a ;DIAG: interface 1 only -- interface 2 (#0B) hung
|
||||||
|
;DIAG: the whole machine on real hardware, do not retry it
|
||||||
|
|
||||||
|
di ;DIAG: off_int_dma alone didn't help -- try a real interrupt
|
||||||
|
;DIAG: mask, in case int_main pages away our resident slot
|
||||||
|
;DIAG: mid-read (not just an SPI timing issue)
|
||||||
|
call sdraw_init
|
||||||
|
or a
|
||||||
|
jp nz,test_sd_raw_noc
|
||||||
|
|
||||||
|
call sdraw_read0
|
||||||
|
or a
|
||||||
|
jp nz,test_sd_raw_rderr
|
||||||
|
;DIAG: keep DI held through the prints too now -- ei was previously
|
||||||
|
;DIAG: right here, leaving a window for int_main to run between the
|
||||||
|
;DIAG: read and the dump; test whether that window is the culprit
|
||||||
|
|
||||||
|
;DIAG: show the raw command handshake bytes -- R1 response after
|
||||||
|
;DIAG: CMD18, and the token byte WTDO settled on (should be #FE)
|
||||||
|
ld a,(sdraw_last_r1)
|
||||||
|
ld de,sdraw_hexbuf3
|
||||||
|
call sdraw_hexch_pair
|
||||||
|
ld a,(sdraw_last_token)
|
||||||
|
ld de,sdraw_hexbuf3+2
|
||||||
|
call sdraw_hexch_pair
|
||||||
|
xor a
|
||||||
|
ld (sdraw_hexbuf3+4),a
|
||||||
|
ld (sdraw_hexbuf3+5),a
|
||||||
|
ld hl,sdraw_r1tok_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ld hl,sdraw_hexbuf3
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
|
||||||
|
;DIAG: always dump [0..15] and [508..511] before judging the signature,
|
||||||
|
;DIAG: so a mismatch shows real vs. garbage/shifted bytes instead of guessing
|
||||||
|
ld hl,sdraw_buf
|
||||||
|
ld de,sdraw_hexbuf
|
||||||
|
ld b,16
|
||||||
|
call sdraw_hexdump
|
||||||
|
ld hl,sdraw_head_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ld hl,sdraw_hexbuf
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
|
||||||
|
ld hl,sdraw_buf+508
|
||||||
|
ld de,sdraw_hexbuf2
|
||||||
|
ld b,4
|
||||||
|
call sdraw_hexdump
|
||||||
|
ld hl,sdraw_tail_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ld hl,sdraw_hexbuf2
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
|
||||||
|
;DIAG: read LBA0 again, right now, and dump it too -- same bytes as
|
||||||
|
;DIAG: above would mean a deterministic bug in our code, not a flaky card
|
||||||
|
call sdraw_read0
|
||||||
|
or a
|
||||||
|
jr nz,test_sd_raw_rderr
|
||||||
|
ld hl,sdraw_buf
|
||||||
|
ld de,sdraw_hexbuf
|
||||||
|
ld b,16
|
||||||
|
call sdraw_hexdump
|
||||||
|
ld hl,sdraw_head2_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ld hl,sdraw_hexbuf
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
|
||||||
|
ld hl,sdraw_buf+510
|
||||||
|
ld a,(hl)
|
||||||
|
cp #55
|
||||||
|
jr nz,test_sd_raw_sigerr
|
||||||
|
inc hl
|
||||||
|
ld a,(hl)
|
||||||
|
cp #aa
|
||||||
|
jr nz,test_sd_raw_sigerr
|
||||||
|
|
||||||
|
;DIAG: now read a totally different LBA (1000, not 0) -- does the
|
||||||
|
;DIAG: garbage pattern shift/change, or stay pinned to the same values?
|
||||||
|
ld hl,0
|
||||||
|
ld de,1000
|
||||||
|
call sdraw_readlba
|
||||||
|
or a
|
||||||
|
jr nz,test_sd_raw_rderr
|
||||||
|
ld hl,sdraw_buf
|
||||||
|
ld de,sdraw_hexbuf
|
||||||
|
ld b,16
|
||||||
|
call sdraw_hexdump
|
||||||
|
ld hl,sdraw_lba1000_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ld hl,sdraw_hexbuf
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
|
||||||
|
ei ;DIAG: only now, after every print, re-enable interrupts
|
||||||
|
ld hl,sdraw_ok_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ret
|
||||||
|
|
||||||
|
test_sd_raw_noc
|
||||||
|
ei
|
||||||
|
ld hl,sdraw_noc_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ret
|
||||||
|
test_sd_raw_rderr
|
||||||
|
ei
|
||||||
|
ld hl,sdraw_rderr_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ret
|
||||||
|
test_sd_raw_sigerr
|
||||||
|
ei
|
||||||
|
ld hl,sdraw_sigerr_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_noc_msg db 'SD raw test: FAIL, no card found',0,0
|
||||||
|
sdraw_rderr_msg db 'SD raw test: FAIL, read error',0,0
|
||||||
|
sdraw_sigerr_msg db 'SD raw test: no 55 AA signature (see above)',0,0
|
||||||
|
sdraw_ok_msg db 'SD raw test: OK, signature valid',0,0
|
||||||
|
sdraw_head_msg db 'sector0[0..15]=',0,0
|
||||||
|
sdraw_head2_msg db '2nd read[0..15]=',0,0
|
||||||
|
sdraw_lba1000_msg db 'LBA1000[0..15]=',0,0
|
||||||
|
sdraw_tail_msg db 'sector0[508..511]=',0,0
|
||||||
|
sdraw_r1tok_msg db 'R1,token=',0,0
|
||||||
|
sdraw_iface_msg db 'interface CS_ON=',0,0
|
||||||
|
sdraw_hexbuf ds 40
|
||||||
|
sdraw_hexbuf2 ds 16
|
||||||
|
sdraw_hexbuf3 ds 8
|
||||||
|
sdraw_last_r1 ds 1
|
||||||
|
sdraw_last_token ds 1
|
||||||
|
|
||||||
|
sdraw_CONF equ #77
|
||||||
|
sdraw_DATA equ #57
|
||||||
|
|
||||||
|
;--- convert A into 2 hex ASCII chars at (DE) ---
|
||||||
|
sdraw_hexch_pair
|
||||||
|
push af
|
||||||
|
rra
|
||||||
|
rra
|
||||||
|
rra
|
||||||
|
rra
|
||||||
|
call sdraw_hexch
|
||||||
|
ld (de),a
|
||||||
|
inc de
|
||||||
|
pop af
|
||||||
|
call sdraw_hexch
|
||||||
|
ld (de),a
|
||||||
|
ret
|
||||||
|
|
||||||
|
;--- hex dump helper: HL=src, DE=dest ascii buffer, B=byte count ---
|
||||||
|
sdraw_hexdump
|
||||||
|
ld a,(hl)
|
||||||
|
push af
|
||||||
|
rra
|
||||||
|
rra
|
||||||
|
rra
|
||||||
|
rra
|
||||||
|
call sdraw_hexch
|
||||||
|
ld (de),a
|
||||||
|
inc de
|
||||||
|
pop af
|
||||||
|
call sdraw_hexch
|
||||||
|
ld (de),a
|
||||||
|
inc de
|
||||||
|
inc hl
|
||||||
|
djnz sdraw_hexdump
|
||||||
|
xor a
|
||||||
|
ld (de),a
|
||||||
|
inc de
|
||||||
|
ld (de),a
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_hexch
|
||||||
|
and #0f
|
||||||
|
cp 10
|
||||||
|
jr c,1f
|
||||||
|
add a,7
|
||||||
|
1 add a,'0'
|
||||||
|
ret
|
||||||
|
|
||||||
|
;--- low-level SD-over-SPI primitives, ported from source/DSDZC.ASM (Wild
|
||||||
|
;--- Commander Improved) which targets the same ZX Evolution SD controller.
|
||||||
|
sdraw_csh
|
||||||
|
push bc
|
||||||
|
push af
|
||||||
|
ld bc,sdraw_CONF
|
||||||
|
ld a,%00000011
|
||||||
|
out (c),a
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
ld a,#ff
|
||||||
|
out (c),a
|
||||||
|
pop af
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_csl_val db %00000001 ;DIAG: interface 1 by default; test_sd_raw
|
||||||
|
;DIAG: flips this to %00001011 (interface 2)
|
||||||
|
;DIAG: if interface 1's signature check fails
|
||||||
|
sdraw_csl
|
||||||
|
push bc
|
||||||
|
push af
|
||||||
|
ld bc,sdraw_CONF
|
||||||
|
ld a,(sdraw_csl_val)
|
||||||
|
out (c),a
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
ld a,#ff
|
||||||
|
out (c),a
|
||||||
|
pop af
|
||||||
|
pop bc
|
||||||
|
jp sdraw_wait
|
||||||
|
|
||||||
|
sdraw_wait
|
||||||
|
push bc
|
||||||
|
push af
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
ld de,60000
|
||||||
|
1 in a,(c)
|
||||||
|
inc a
|
||||||
|
jr z,2f
|
||||||
|
dec de
|
||||||
|
ld a,d
|
||||||
|
or e
|
||||||
|
jr nz,1b
|
||||||
|
2 pop af
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_wtdo
|
||||||
|
push bc
|
||||||
|
push de
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
ld de,60000
|
||||||
|
1 in a,(c)
|
||||||
|
cp #ff
|
||||||
|
jr nz,2f
|
||||||
|
dec de
|
||||||
|
ld a,d
|
||||||
|
or e
|
||||||
|
jr nz,1b
|
||||||
|
2 pop de
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_resp
|
||||||
|
push de
|
||||||
|
push bc
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
ld d,10
|
||||||
|
1 in a,(c)
|
||||||
|
bit 7,a
|
||||||
|
jr z,2f
|
||||||
|
dec d
|
||||||
|
jr nz,1b
|
||||||
|
inc d
|
||||||
|
2 pop bc
|
||||||
|
pop de
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_cycl ; DE = number of #FF clock bytes to send
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
1 ld a,#ff
|
||||||
|
out (c),a
|
||||||
|
dec de
|
||||||
|
ld a,d
|
||||||
|
or e
|
||||||
|
jr nz,1b
|
||||||
|
ret
|
||||||
|
|
||||||
|
;--- send a pre-built 6-byte command frame pointed to by HL (real CRC).
|
||||||
|
;--- Matches D:\ST\ZP\PLAY60.ASM's actual shipped timing (not the blog
|
||||||
|
;--- article, which the article's own author -- who wrote that player --
|
||||||
|
;--- says has bugs): two dummy IN (C) reads before the frame ("; savelij"
|
||||||
|
;--- in the source), and a NOP between each byte sent. Without this, the
|
||||||
|
;--- handshake (R1/token) still looks valid but the payload comes back as
|
||||||
|
;--- deterministic garbage -- exactly what we were seeing.
|
||||||
|
sdraw_cmd
|
||||||
|
call sdraw_csh
|
||||||
|
call sdraw_csl
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
in (c)
|
||||||
|
in (c)
|
||||||
|
outi
|
||||||
|
nop
|
||||||
|
outi
|
||||||
|
nop
|
||||||
|
outi
|
||||||
|
nop
|
||||||
|
outi
|
||||||
|
nop
|
||||||
|
outi
|
||||||
|
nop
|
||||||
|
outi
|
||||||
|
jp sdraw_resp
|
||||||
|
|
||||||
|
;--- send a simple command: A=opcode, all-zero args, CRC=#FF ---
|
||||||
|
sdraw_cmdo
|
||||||
|
call sdraw_csh
|
||||||
|
call sdraw_csl
|
||||||
|
sdraw_cmdx
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
in (c)
|
||||||
|
in (c)
|
||||||
|
out (c),a
|
||||||
|
xor a
|
||||||
|
out (c),a
|
||||||
|
nop
|
||||||
|
out (c),a
|
||||||
|
nop
|
||||||
|
out (c),a
|
||||||
|
nop
|
||||||
|
out (c),a
|
||||||
|
ld a,#ff
|
||||||
|
out (c),a
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_cmd00 db %01000000+0,0,0,0,0,#95
|
||||||
|
sdraw_cmd08 db %01000000+8,0,0,1,#aa,#87
|
||||||
|
sdraw_cmd16 db %01000000+16,0,0,2,0,#ff
|
||||||
|
|
||||||
|
sdraw_do_cmd0 ld hl,sdraw_cmd00
|
||||||
|
jp sdraw_cmd
|
||||||
|
sdraw_do_cmd8 ld hl,sdraw_cmd08
|
||||||
|
jp sdraw_cmd
|
||||||
|
sdraw_do_cmd16 ld hl,sdraw_cmd16
|
||||||
|
jp sdraw_cmd
|
||||||
|
sdraw_do_cmd1 ld a,%01000000+1
|
||||||
|
call sdraw_cmdo
|
||||||
|
jp sdraw_resp
|
||||||
|
sdraw_do_cmd55 ld a,%01000000+55
|
||||||
|
call sdraw_cmdo
|
||||||
|
jp sdraw_resp
|
||||||
|
|
||||||
|
;--- ACMD41: H = argument high byte (0, or #40 for HCS), rest zero ---
|
||||||
|
sdraw_do_acmd41
|
||||||
|
call sdraw_do_cmd55
|
||||||
|
call sdraw_csh
|
||||||
|
call sdraw_csl
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
in (c)
|
||||||
|
in (c)
|
||||||
|
ld a,%01000000+41
|
||||||
|
out (c),a
|
||||||
|
ld l,0
|
||||||
|
out (c),h
|
||||||
|
nop
|
||||||
|
out (c),l
|
||||||
|
nop
|
||||||
|
out (c),l
|
||||||
|
nop
|
||||||
|
out (c),l
|
||||||
|
dec l
|
||||||
|
out (c),l
|
||||||
|
jp sdraw_resp
|
||||||
|
|
||||||
|
;--- card init: CMD0/CMD8/ACMD41 (SDv2), falls back to ACMD41/CMD1 (SDv1/MMC)
|
||||||
|
; A=0 on success, A=1 on failure
|
||||||
|
sdraw_init
|
||||||
|
call sdraw_csh
|
||||||
|
ld de,512+10
|
||||||
|
call sdraw_cycl
|
||||||
|
|
||||||
|
ld de,8000
|
||||||
|
1 dec de
|
||||||
|
ld a,d
|
||||||
|
or e
|
||||||
|
jp z,sdraw_init_fail
|
||||||
|
call sdraw_do_cmd0
|
||||||
|
jr nz,1b
|
||||||
|
dec a
|
||||||
|
jp nz,1b
|
||||||
|
|
||||||
|
call sdraw_do_cmd8
|
||||||
|
push af
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
in e,(c)
|
||||||
|
nop
|
||||||
|
in e,(c)
|
||||||
|
nop
|
||||||
|
in h,(c)
|
||||||
|
nop
|
||||||
|
in l,(c)
|
||||||
|
pop af
|
||||||
|
jr nz,1b
|
||||||
|
bit 2,a
|
||||||
|
jr z,sdraw_v2
|
||||||
|
|
||||||
|
;--- legacy path: SDv1 (ACMD41) then MMC (CMD1) ---
|
||||||
|
ld de,8000
|
||||||
|
2 dec de
|
||||||
|
ld a,d
|
||||||
|
or e
|
||||||
|
jr z,3f
|
||||||
|
ld h,0
|
||||||
|
call sdraw_do_acmd41
|
||||||
|
jr nz,2b
|
||||||
|
cp 1
|
||||||
|
jr z,2b
|
||||||
|
or a
|
||||||
|
jr nz,3f
|
||||||
|
jr sdraw_fbs
|
||||||
|
|
||||||
|
3 ld de,8000
|
||||||
|
4 dec de
|
||||||
|
ld a,d
|
||||||
|
or e
|
||||||
|
jr z,sdraw_init_fail
|
||||||
|
call sdraw_do_cmd1
|
||||||
|
jr nz,4b
|
||||||
|
cp 1
|
||||||
|
jr z,4b
|
||||||
|
or a
|
||||||
|
jr nz,sdraw_init_fail
|
||||||
|
|
||||||
|
sdraw_fbs call sdraw_do_cmd16
|
||||||
|
jr nz,sdraw_init_fail
|
||||||
|
or a
|
||||||
|
jr nz,sdraw_init_fail
|
||||||
|
jr sdraw_init_ok
|
||||||
|
|
||||||
|
;--- SDv2 path: verify the 0x1AA echo pattern from CMD8, then ACMD41+HCS ---
|
||||||
|
sdraw_v2 ld de,#01aa
|
||||||
|
or a
|
||||||
|
sbc hl,de
|
||||||
|
jr nz,sdraw_init_fail
|
||||||
|
|
||||||
|
ld de,8000
|
||||||
|
5 dec de
|
||||||
|
ld a,d
|
||||||
|
or e
|
||||||
|
jr z,sdraw_init_fail
|
||||||
|
ld h,#40
|
||||||
|
call sdraw_do_acmd41
|
||||||
|
jr nz,5b
|
||||||
|
cp 1
|
||||||
|
jr z,5b
|
||||||
|
or a
|
||||||
|
jr nz,sdraw_init_fail
|
||||||
|
; not distinguishing byte/block addressing (CMD58/CCS) here --
|
||||||
|
; irrelevant for reading LBA 0, which is address 0 either way.
|
||||||
|
|
||||||
|
sdraw_init_ok
|
||||||
|
call sdraw_csh
|
||||||
|
xor a
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_init_fail
|
||||||
|
call sdraw_csh
|
||||||
|
xor a
|
||||||
|
inc a
|
||||||
|
ret
|
||||||
|
|
||||||
|
;--- read LBA 0 (single 512-byte sector) into sdraw_buf ---
|
||||||
|
; A=0 on success, A=1 on failure
|
||||||
|
sdraw_read0
|
||||||
|
ld hl,0
|
||||||
|
ld de,0
|
||||||
|
jp sdraw_readlba
|
||||||
|
|
||||||
|
;--- read an arbitrary LBA (single 512-byte sector) via CMD18+CMD12 into
|
||||||
|
;--- sdraw_buf. Matches the proven reference implementation in D:\ST\ZP's
|
||||||
|
;--- Z-Player source (SD-CARD2.TXT / PLAY60.ASM) byte-for-byte in approach:
|
||||||
|
;--- CMD18 (not CMD17!) for the read, and INI (not manual IN+LD(HL),A) for
|
||||||
|
;--- the bulk 512-byte transfer.
|
||||||
|
; HL = LBA bits31-16, DE = LBA bits15-0
|
||||||
|
; A=0 on success, A=1 on failure
|
||||||
|
sdraw_readlba
|
||||||
|
call sdraw_csh
|
||||||
|
call sdraw_csl
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
in (c) ;DIAG: settling reads + inter-byte NOPs, matching
|
||||||
|
in (c) ;DIAG: PLAY60.ASM's CMzz exactly (see sdraw_cmd)
|
||||||
|
ld a,%01000000+18
|
||||||
|
out (c),a
|
||||||
|
nop
|
||||||
|
out (c),h
|
||||||
|
nop
|
||||||
|
out (c),l
|
||||||
|
nop
|
||||||
|
out (c),d
|
||||||
|
nop
|
||||||
|
out (c),e
|
||||||
|
ld a,#ff
|
||||||
|
out (c),a
|
||||||
|
call sdraw_resp
|
||||||
|
ld (sdraw_last_r1),a ;DIAG: record for display, whatever the outcome
|
||||||
|
or a
|
||||||
|
jr nz,sdraw_readlba_fail
|
||||||
|
|
||||||
|
call sdraw_wtdo
|
||||||
|
ld (sdraw_last_token),a ;DIAG: record for display, whatever the outcome
|
||||||
|
cp #fe
|
||||||
|
jr nz,sdraw_readlba_fail
|
||||||
|
|
||||||
|
;DIAG: manual IN+store loop, reloading BC (so B is pinned at 0) before
|
||||||
|
;DIAG: every single byte -- ruling out B-register drift across INI's
|
||||||
|
;DIAG: as a hardware port-decode issue, however unlikely
|
||||||
|
ld hl,sdraw_buf
|
||||||
|
ld e,32
|
||||||
|
1 ld b,16
|
||||||
|
2 ld c,sdraw_DATA
|
||||||
|
in a,(c)
|
||||||
|
ld (hl),a
|
||||||
|
inc hl
|
||||||
|
djnz 2b
|
||||||
|
dec e
|
||||||
|
jr nz,1b
|
||||||
|
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
in a,(c) ; discard 2 CRC bytes
|
||||||
|
in a,(c)
|
||||||
|
|
||||||
|
call sdraw_do_cmd12
|
||||||
|
call sdraw_snb
|
||||||
|
call sdraw_wtby
|
||||||
|
call sdraw_csh
|
||||||
|
xor a
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_readlba_fail
|
||||||
|
call sdraw_csh
|
||||||
|
xor a
|
||||||
|
inc a
|
||||||
|
ret
|
||||||
|
|
||||||
|
;--- stop a multi-block transfer (CMD12). Sent without a fresh CSH/CSL --
|
||||||
|
;--- the card is still selected from the CMD18 that started the transfer.
|
||||||
|
sdraw_do_cmd12
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
ld a,%01000000+12
|
||||||
|
out (c),a
|
||||||
|
xor a
|
||||||
|
out (c),a
|
||||||
|
out (c),a
|
||||||
|
out (c),a
|
||||||
|
out (c),a
|
||||||
|
ld a,#ff
|
||||||
|
out (c),a
|
||||||
|
xor a
|
||||||
|
in a,(sdraw_DATA) ; one stuff byte before the R1 response, per spec
|
||||||
|
jp sdraw_resp
|
||||||
|
|
||||||
|
sdraw_snb
|
||||||
|
push bc
|
||||||
|
ld b,16
|
||||||
|
1 xor a
|
||||||
|
in a,(sdraw_DATA)
|
||||||
|
djnz 1b
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_wtby
|
||||||
|
push bc
|
||||||
|
ld bc,sdraw_DATA
|
||||||
|
1 in a,(c)
|
||||||
|
or a
|
||||||
|
jr z,1b
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
|
||||||
|
;DIAG: step 2 - parse the FAT32 BPB (already validated in sdraw_buf's first
|
||||||
|
;DIAG: 16 bytes), locate the root directory, find ZIFI.INI's short-name
|
||||||
|
;DIAG: entry there, and read+print its first line. Proves we can navigate
|
||||||
|
;DIAG: the filesystem and read a real file, not just a raw sector.
|
||||||
|
test_sd_raw2
|
||||||
|
di ;DIAG: real interrupt mask, see test_sd_raw
|
||||||
|
call sdraw_read0
|
||||||
|
or a
|
||||||
|
jp nz,t2_fail
|
||||||
|
|
||||||
|
ld a,(sdraw_buf+13)
|
||||||
|
ld (sdraw_secpclus),a
|
||||||
|
|
||||||
|
; acc(32-bit) = reservedSectors
|
||||||
|
ld hl,(sdraw_buf+14)
|
||||||
|
ld (sdraw_acc_lo),hl
|
||||||
|
ld hl,0
|
||||||
|
ld (sdraw_acc_hi),hl
|
||||||
|
|
||||||
|
; acc += FATSz32 * numFATs
|
||||||
|
ld hl,(sdraw_buf+36)
|
||||||
|
ld (sdraw_fatsz_lo),hl
|
||||||
|
ld hl,(sdraw_buf+38)
|
||||||
|
ld (sdraw_fatsz_hi),hl
|
||||||
|
ld a,(sdraw_buf+16)
|
||||||
|
ld b,a
|
||||||
|
or a
|
||||||
|
jr z,t2_fatdone
|
||||||
|
t2_fatloop
|
||||||
|
push bc
|
||||||
|
ld hl,(sdraw_fatsz_lo)
|
||||||
|
ld de,(sdraw_fatsz_hi)
|
||||||
|
call sdraw_acc_add32
|
||||||
|
pop bc
|
||||||
|
djnz t2_fatloop
|
||||||
|
t2_fatdone
|
||||||
|
; acc now = firstDataSector -- save it, needed again for the file itself
|
||||||
|
ld hl,(sdraw_acc_lo)
|
||||||
|
ld (sdraw_firstdata_lo),hl
|
||||||
|
ld hl,(sdraw_acc_hi)
|
||||||
|
ld (sdraw_firstdata_hi),hl
|
||||||
|
|
||||||
|
; acc += (rootCluster-2) * sectorsPerCluster
|
||||||
|
ld hl,(sdraw_buf+44)
|
||||||
|
ld de,2
|
||||||
|
or a
|
||||||
|
sbc hl,de
|
||||||
|
ld b,h
|
||||||
|
ld c,l
|
||||||
|
t2_clusloop
|
||||||
|
ld a,b
|
||||||
|
or c
|
||||||
|
jr z,t2_clusdone
|
||||||
|
push bc
|
||||||
|
ld a,(sdraw_secpclus)
|
||||||
|
ld l,a
|
||||||
|
ld h,0
|
||||||
|
ld de,0
|
||||||
|
call sdraw_acc_add32
|
||||||
|
pop bc
|
||||||
|
dec bc
|
||||||
|
jr t2_clusloop
|
||||||
|
t2_clusdone
|
||||||
|
ld hl,(sdraw_acc_hi)
|
||||||
|
ld de,(sdraw_acc_lo)
|
||||||
|
call sdraw_readlba
|
||||||
|
or a
|
||||||
|
jp nz,t2_fail
|
||||||
|
|
||||||
|
ld hl,sdraw_buf
|
||||||
|
t2_scan
|
||||||
|
ld a,h
|
||||||
|
cp high (sdraw_buf+512)
|
||||||
|
jr nz,t2_chk
|
||||||
|
ld a,l
|
||||||
|
cp low (sdraw_buf+512)
|
||||||
|
jr z,t2_notfound
|
||||||
|
t2_chk
|
||||||
|
push hl
|
||||||
|
ld de,sdraw_zifiini_name
|
||||||
|
ld b,11
|
||||||
|
1 ld a,(de)
|
||||||
|
cp (hl)
|
||||||
|
jr nz,2f
|
||||||
|
inc hl
|
||||||
|
inc de
|
||||||
|
djnz 1b
|
||||||
|
pop hl
|
||||||
|
jr t2_found
|
||||||
|
2 pop hl
|
||||||
|
ld de,32
|
||||||
|
add hl,de
|
||||||
|
jr t2_scan
|
||||||
|
|
||||||
|
t2_found
|
||||||
|
; extract starting cluster: low word @ entry+26, high word @ entry+20
|
||||||
|
push hl
|
||||||
|
ld de,26
|
||||||
|
add hl,de
|
||||||
|
ld a,(hl)
|
||||||
|
inc hl
|
||||||
|
ld h,(hl)
|
||||||
|
ld l,a
|
||||||
|
ld (sdraw_filecl_lo),hl
|
||||||
|
pop hl
|
||||||
|
push hl
|
||||||
|
ld de,20
|
||||||
|
add hl,de
|
||||||
|
ld a,(hl)
|
||||||
|
inc hl
|
||||||
|
ld h,(hl)
|
||||||
|
ld l,a
|
||||||
|
ld (sdraw_filecl_hi),hl
|
||||||
|
pop hl
|
||||||
|
|
||||||
|
; acc = firstDataSector + (fileCluster-2)*sectorsPerCluster
|
||||||
|
ld hl,(sdraw_firstdata_lo)
|
||||||
|
ld (sdraw_acc_lo),hl
|
||||||
|
ld hl,(sdraw_firstdata_hi)
|
||||||
|
ld (sdraw_acc_hi),hl
|
||||||
|
|
||||||
|
ld hl,(sdraw_filecl_lo)
|
||||||
|
ld de,2
|
||||||
|
or a
|
||||||
|
sbc hl,de
|
||||||
|
ld b,h
|
||||||
|
ld c,l
|
||||||
|
t2_fclusloop
|
||||||
|
ld a,b
|
||||||
|
or c
|
||||||
|
jr z,t2_fclusdone
|
||||||
|
push bc
|
||||||
|
ld a,(sdraw_secpclus)
|
||||||
|
ld l,a
|
||||||
|
ld h,0
|
||||||
|
ld de,0
|
||||||
|
call sdraw_acc_add32
|
||||||
|
pop bc
|
||||||
|
dec bc
|
||||||
|
jr t2_fclusloop
|
||||||
|
t2_fclusdone
|
||||||
|
ld hl,(sdraw_acc_hi)
|
||||||
|
ld de,(sdraw_acc_lo)
|
||||||
|
call sdraw_readlba
|
||||||
|
or a
|
||||||
|
jr nz,t2_fail
|
||||||
|
|
||||||
|
ei
|
||||||
|
ld hl,sdraw_found_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ld hl,sdraw_buf
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ret
|
||||||
|
|
||||||
|
t2_notfound
|
||||||
|
ei
|
||||||
|
ld hl,sdraw_notfound_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ret
|
||||||
|
t2_fail
|
||||||
|
ei
|
||||||
|
ld hl,sdraw_fail2_msg
|
||||||
|
ld b,1
|
||||||
|
call zifi_echo
|
||||||
|
ret
|
||||||
|
|
||||||
|
; adds a 32-bit value (DE=high word, HL=low word) into the 32-bit
|
||||||
|
; accumulator sdraw_acc_hi:sdraw_acc_lo
|
||||||
|
sdraw_acc_add32
|
||||||
|
push de
|
||||||
|
ld de,(sdraw_acc_lo)
|
||||||
|
add hl,de
|
||||||
|
ld (sdraw_acc_lo),hl
|
||||||
|
pop hl
|
||||||
|
ld de,(sdraw_acc_hi)
|
||||||
|
adc hl,de
|
||||||
|
ld (sdraw_acc_hi),hl
|
||||||
|
ret
|
||||||
|
|
||||||
|
sdraw_found_msg db 'ZIFI.INI found, first line:',0,0
|
||||||
|
sdraw_notfound_msg db 'ZIFI.INI not found in root dir sector0',0,0
|
||||||
|
sdraw_fail2_msg db 'SD raw test2: FAIL',0,0
|
||||||
|
sdraw_zifiini_name db "ZIFI INI"
|
||||||
|
|
||||||
|
sdraw_secpclus ds 1
|
||||||
|
sdraw_acc_lo ds 2
|
||||||
|
sdraw_acc_hi ds 2
|
||||||
|
sdraw_fatsz_lo ds 2
|
||||||
|
sdraw_fatsz_hi ds 2
|
||||||
|
sdraw_firstdata_lo ds 2
|
||||||
|
sdraw_firstdata_hi ds 2
|
||||||
|
sdraw_filecl_lo ds 2
|
||||||
|
sdraw_filecl_hi ds 2
|
||||||
|
|
||||||
|
align 256
|
||||||
|
sdraw_buf ds 512
|
||||||
|
;DIAG: end of standalone raw SD-card test block
|
||||||
|
|
||||||
sd_init
|
sd_init
|
||||||
call init_sd_card
|
call init_sd_card
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user