sdc: make sector swapping more robust

It would previously only work when GetC-ing our way into a new sector.
Seeking into one would not work. Now it's much more robust and this
paves the way for write support.
This commit is contained in:
Virgil Dupras 2019-05-30 14:55:38 -04:00
parent cdc865f8c6
commit a641a94853
1 changed files with 39 additions and 27 deletions

View File

@ -31,7 +31,13 @@
; Whenever we read a sector, we read a whole block at once and we store it ; Whenever we read a sector, we read a whole block at once and we store it
; in memory. That's where it goes. ; in memory. That's where it goes.
.equ SDC_BUF SDC_PTR+2 .equ SDC_BUF SDC_PTR+2
.equ SDC_RAMEND SDC_BUF+SDC_BLKSIZE ; Sector number currently in SDC_BUF. 0xff, it's initial value, means "no
; sector.
.equ SDC_BUFSEC SDC_BUF+SDC_BLKSIZE
; Whether the buffer has been written to. 0 means clean. 1 means dirty.
; (not used yet)
.equ SDC_BUFDIRTY SDC_BUFSEC+1
.equ SDC_RAMEND SDC_BUFDIRTY+1
; *** Code *** ; *** Code ***
; Wake the SD card up. After power up, a SD card has to receive at least 74 ; Wake the SD card up. After power up, a SD card has to receive at least 74
@ -212,17 +218,17 @@ sdcInitialize:
or a ; cp 0 or a ; cp 0
jr nz, .error jr nz, .error
; Success! out of idle mode! ; Success! out of idle mode!
; We initialize out current PTR to 0 ; initialize variables
ld hl, 0 ld hl, 0
ld (SDC_PTR), hl ld (SDC_PTR), hl
jr .success ld a, 0xff
ld (SDC_BUFSEC), a
xor a
ld (SDC_BUFDIRTY), a
jr .end
.error: .error:
ld a, 0x01 ld a, 0x01
jr .end
.success:
xor a
.end: .end:
pop bc pop bc
pop de pop de
@ -246,7 +252,8 @@ sdcSetBlkSize:
ret ret
; Read block index specified in A and place the contents in (SDC_BUF). ; Read block index specified in A and place the contents in (SDC_BUF).
; Doesn't check CRC. ; Doesn't check CRC. If the operation is a success, updates (SDC_BUFSEC) to the
; value of A.
; Returns 0 in A if success, non-zero if error. ; Returns 0 in A if success, non-zero if error.
sdcReadBlk: sdcReadBlk:
push bc push bc
@ -255,7 +262,8 @@ sdcReadBlk:
out (SDC_PORT_CSLOW), a out (SDC_PORT_CSLOW), a
ld hl, 0 ; read single block at addr A ld hl, 0 ; read single block at addr A
ld d, 0 ld d, 0
ld e, a ld e, a ; E isn't touched in the rest of the routine
; and holds onto our original A
ld a, 0b01010001 ; CMD17 ld a, 0b01010001 ; CMD17
call sdcCmd call sdcCmd
or a ; cp 0 or a ; cp 0
@ -286,8 +294,11 @@ sdcReadBlk:
; Read our 2 CRC bytes ; Read our 2 CRC bytes
call sdcWaitResp call sdcWaitResp
call sdcWaitResp call sdcWaitResp
; success! ; success! Let's recall our orginal A arg and put it in SDC_BUFSEC
ld a, e
ld (SDC_BUFSEC), a
xor a xor a
ld (SDC_BUFDIRTY), a
jr .end jr .end
.error: .error:
; try to preserve error code ; try to preserve error code
@ -312,24 +323,24 @@ sdcInitializeCmd:
sdcGetC: sdcGetC:
; SDC_PTR points to the character we're supposed to read right now, but ; SDC_PTR points to the character we're supposed to read right now, but
; we first have to check whether we need to load a new sector in memory. ; we first have to check whether we need to load a new sector in memory.
; This is rather easy: if the first 9 bits are zero, then we need to ; To do this, we compare the high 7 bits of (SDC_PTR) with (SDC_BUFSEC).
; read the sector in the high 7 bits. ; If they're different, we need to load a new block.
push hl push hl
ld a, (SDC_BUFSEC)
xor a ld h, a
ld hl, (SDC_PTR) ld a, (SDC_PTR+1) ; high byte has bufsec in its high 7 bits
bit 0, h srl a
jr nz, .highbuf ; first bit set? no need to read a sector. Also, cp h
; we already know that we're in the "highbuf" jr z, .noload
; zone. ; not equal, we need to load a new sector. A already contains the
cp l ; is L zero? ; sector to load.
jr nz, .lowbuf ; non-zero? no need to read a sector
; Oh, first 9 bits unset. Se need to read a sector
ld a, h
rrca ; now that's our sector
call sdcReadBlk call sdcReadBlk
jr nz, .error jr nz, .error
.lowbuf: .noload:
ld a, (SDC_PTR+1) ; high byte
and 0x01 ; is first bit set?
jr nz, .highbuf ; first bit set? we're in the "highbuf" zone.
; lowbuf zone
; Read byte from memory at proper offset in lowbuf (first 0x100 bytes) ; Read byte from memory at proper offset in lowbuf (first 0x100 bytes)
ld hl, SDC_BUF ld hl, SDC_BUF
jr .read jr .read
@ -347,8 +358,9 @@ sdcGetC:
ld a, (hl) ld a, (hl)
; before we return A, we need to increase (SDC_PTR) ; before we return A, we need to increase (SDC_PTR)
ld hl, SDC_PTR ld hl, (SDC_PTR)
inc (hl) inc hl
ld (SDC_PTR), hl
cp a ; ensure Z cp a ; ensure Z
jr .end jr .end