; CF specific low level routines

;write registers
CFdata     EQU &B0
CFfeature  EQU &B1
CFcount    EQU &B2
CFLBAlow   EQU &B3
CFLBAmid   EQU &B4
CFLBAhigh  EQU &B5
CFLBAtop   EQU &B6
CFcommand  EQU &B7
;
;read registers
CFerr      EQU &B1
CFstatus   EQU &B7

; SDX rom expects to see CFinit, CFread, CFwrite
;
; Initialise CF card
; after:
;   if ok, Z, CF initialised
;   if not ok, NZ, CF not initialised
;
.CPMCFInit
PUSH BC
LD a,CMD_init
OUT (CFcommand),A
;
LD B,0                          ;for the timeout counter
jr init_pass1                 ;jump past the timeout checks on the first pass
.INIT_loop             
dec B                           ;exit if we've tried 256 times and drive still not ready
JR Z cpm_timeout
call cpm_delay                   ;CF doesn't need to spin up, but allow some extra time
                                ;just in case. The 255 calls of the delay routine take
                                ;approx 2.5 sec at 4mhz
.INIT_pass1
in a,(CFstatus)                 ;read status register
bit 7,a                         ;bit 7 is bsy
JR nz INIT_LOOP               ;wait for BSY to be clear
bit 6,a                         ;bit 6 is rdy
JR z INIT_LOOP                ;wait for RDY to be set

ld a,1                          ;set CF 8 bit mode
out (CFfeature),A
ld a,&EF
out (CFcommand),A
call CPMwait_ready

ld a,&82                        ;set no write cache
out (CFfeature),A
ld a,&EF
out (CFcommand),A
call CPMwait_ready

;LD A,%11100000                  ;select the master device. LBA mode
;out (CFLBAtop),A


POP BC
XOR A                           ; A zero'd and ZF set to indicate all OK
RET

.cpm_timeout
POP BC
xor A
DEC A                           ;return A no zero and Z reset 
RET

;waste approx 3339 * 12 is approx 40,000 cycles delay 0.01 sec at 4mhz.
.CPM_delay
push bc
ld BC,12
.Cpm_delay_loop
DJNZ Cpm_delay_loop    ;3323 cycles on inner loop
dec c                    ;4
JR nz Cpm_delay_loop   ;12
pop bc
ret


;
; Read block from CF card
;   before:
;     SDLBA is 32 bit block 512 byte block number, HL is buffer
;   after:
;     if ok, Z
;     if not ok, NZ
;
.CPMCFREAD
PUSH BC
PUSH hl
CALL CpmSetLBA        ;send LBA number to the drive
LD a,CMD_READ
out (CFcommand),A
CALL CpmWAIT_DRQ
AND 1                ;isolate bit 0
JR NZ,CpmGET_ERR      ;error bit set, find out why
LD BC,CFdata         ;C set to the data register INIR count set to zero for 2 x 256
DI
INIR
INIR
EI
pop hl
POP BC
xor A               ;exit with A zero'd and Z set 
RET

; CF routines only requre A=0/Z=1 good or A<>0/Z=0 error
; however error read on return for future expansion 
.CpmGET_ERR
pop hl
POP BC
in a,(CFerr)
AND A
RET NZ
DEC A   ;make sure A isn't zero and the flag isn't set
RET
;
; Write block to CF card
;   before:
;     SDLBA is 32 bit block 512 byte block number, HL is buffer
;   after:
;     if ok, Z
;     if not ok, NZ

.CPMCFwrite
PUSH BC
PUSH HL
CALL CpmSetLBA
LD A,CMD_WRITE
out (CFcommand),A
CALL CpmWAIT_DRQ
AND 1
JR NZ,CpmGET_ERR
ld BC,CFdata           ;C set to the data register OTIR count set to zero for 2 x 256
DI
otir
otir
EI
CALL CpmWAIT_ready
AND 1
JR NZ,CpmGET_ERR
POP HL
POP BC
xor A
RET

;
; Set CF LBA
; corrupts A
.CpmsetLBA
CALL CpmWAIT_ready
LD A,%11100000         ;Top 4 bits of address zero, b4 clear is for LBA master
out (CFLBAtop),A      ;write LBA mode to LBA top byte register
ld A,(CPMsdlba+2)
out (CFLBAhigh),A     ;write to LBA bits 16-23
ld A,(CPMSDLBA+1)
out (CFLBAmid),A      ;write to LBA bits  8-15
ld A,(CPMSDLBA)
out (CFLBAlow),A      ;write to LBA bits  0- 7
LD A,1
out (CFcount),A       ;set the sector count to 1
RET


; wait for device to be both not busy and ready
;Returns the drive's status in A
.CpmWAIT_READY
in A,(CFstatus)          ;read status register
                         ;should probably check for a timeout here
bit 7,a                  ;bit 7 is BSY
JR nz CpmWAIT_READY       ;wait for BSY to be clear so we can get a good read on ready
bit 6,a                  ;bit 6 is ready
JR z CpmWAIT_READY        ;wait for RDY to be set
RET


;Wait for the drive to be ready to transfer data.
;Returns the drive's status in A
.CpmWAIT_DRQ
in A,(CFstatus)          ;read status register
                         ;should probably check for a timeout here
bit 7,a                  ;bit 7 is BSY
JR nz CpmWAIT_DRQ         ;wait for BSY to be clear so we can get a good read on DRQ
bit 3,a                  ;bit 3 is DRQ
JR z CpmWAIT_DRQ          ;wait for DRQ to be set
RET

;   End of 8 bit CF low level routines

END
