 org #100
 nolist
;
;
; FDC Code reading a load of sectors
; and files written with Arkos Disk Writter.
; Without system.
; V1.0
;
; By Targhan/Arkos
;
; Format used by 'Arkos Disk Writter'
; 10 2-sized sectors per track (c1-ca), 42 tracks (0-41)
;
;
;
;
; Proper use =
; call FDCON to turn the drive ON
;
; ld a,drive (0-3)
; ld b,head (0-1)
; call FDCVARS to tell which drive to use, head to read.
;
; ld a,nb sectors to read
; ld b,beginning track (0-41)
; ld c,beginning sector (#c1-#ca)
; ld hl,where to load
; call LOADSCTS to load the sectors
; Return =
; A=state. 0=ok  1=disc missing  2=read fail
;
; When you've loaded all the files you wanted =
; call FDCOFF
;
;
;
; You shouldn't need it, but...
; call RECALIBR
; to recalibrate the current drive (use FDCON
; and FDCVARS first !). AMSDOS does it when you turn
; the CPC on. You can also do it when an error disc
; happened, before trying loading the file again.
;
; That's it !
;
;
; Notes
; - By changing the Head, you can read the file on the second
;    side of a 3"5 disc.
; - No buffer is needed.
; - The interruptions are CUT by the loading code.
; - Interruptions are turned on when turning on the FDC, so
;   put #c9fb in #38 before if you don't want your
;   interruptions code to be run at this moment.
;
;
;
;Maximum number of direction entry of a file. *16 to get the maximum size
;loadable in KB. 4 should be more than enough (=64k).
NBMAXENT equ 4
;
;Track where the directory is. Some AMSDOS tweakings allow to use another one.
DIRTRACK equ 0
;
;First sector of the directory.
DIRFSECT equ #c1
;
;
;
;
;
;Some testing program
;Removing this when included this code to your own.
;----------------------------
 di
 ld hl,#c9fb
 ld (#38),hl
;
 call FDCON
;
 xor a
 ld b,0
 call FDCVARS
;
 ld a,32   ;nb sectors to read
 ld b,0   ;beginning track (0-41)
 ld c,#c1  ;beginning sector (#c1-#ca)
 ld hl,#c000  ;where to load
 call LOADSCTS
 jr nc,ERROR
 call FDCOFF
;
ENDLESS jr ENDLESS
;
ERROR ld bc,#7f10  ;error
 out (c),c
 ld c,#4c
 out (c),c
 jr ENDLESS
;----------------------------
;
;
;
;
;
;
;Tell which drive to use, head to read.
;A=drive (0-3)
;B=head (0-1)
FDCVARS
 ld (FDCDRIVE),a
 ld c,a
 ld a,b
 ld (FDCHEAD),a
 rla
 rla
 and %100
 or c
 ld (FDCIDDR),a
 ret
;
;
;
;
;Turn FDC on and wait a bit.
FDCON    LD   A,(FDCMOTOR)
         OR   A
         RET  NZ
         INC  A
         LD   (FDCMOTOR),A
         LD   BC,#FA7E
         LD   A,1
         OUT  (C),A
  EI      ;Wait for motor to get full speed
         LD   B,6*30
WAIT     HALT 
         DJNZ WAIT
         DI   
         RET  
;
;
;
;
;Turn FDC off.
FDCOFF   XOR  A
         LD   (FDCMOTOR),A
         LD   BC,#FA7E
         XOR  A
         OUT  (C),A
         RET  
;
;
;
;Recalibrate current drive.
RECALIBR
 call RECALIB2
 call RECALIB2
 ret
RECALIB2
         LD   A,%00000111
         CALL PUTFDC
  ld a,(FDCIDDR)
         CALL PUTFDC
         CALL WAITEND
         RET  
;
;
;
;
;Load sectors in memory.
;ld a,nb sectors to read
;ld b,beginning track (0-41)
;ld c,beginning sector (#c1-#ca)
;ld hl,where to load
;Return =
;A=state. 0=ok  1=disc missing  2=read fail
LOADSCTS
 ld (LOADWHER),hl
;
 ld (LSNBS+1),a
 ld a,b
 ld (LSTRACK+1),a
 ld a,c
 ld (LSSECT+1),a
;
;
;Reading the sectors
LOADLP
;
LSTRACK ld a,0
LSSECT ld b,0
 ld hl,(LOADWHER)
 CALL READSECT
 ret nc
;
LSNBS ld a,0   ;Nb sectors to read yet.
 dec a
 jr z,LOADFOK
 ld (LSNBS+1),a
;
 ld hl,(LOADWHER)
 ld de,#200
 add hl,de
 ld (LOADWHER),hl
;
 ld a,(LSSECT+1)  ;Go to next sector
 inc a
 cp #cb
 jr nz,LPNSF
 ld hl,LSTRACK+1
 inc (hl)
 ld a,#c1
LPNSF ld (LSSECT+1),a
;
 jr LOADLP
;
LOADFOK scf
 ret
;
;
;
;
;
;
;Wait for the end of the current instruction (using ST0).
WAITEND
         LD   A,%00001000
         CALL PUTFDC
         CALL GETFDC                    ;Get ST0
         LD   (ST0),A
         CALL GETFDC
         XOR  A
         LD   (ST1),A                   ;Reset ST1 and ST2
         LD   (ST2),A
;
         LD   A,(ST0)
         BIT  5,A                       ;Instruction over ?
         JR   Z,WAITEND
         RET  
;
;Send data to FDC
;A=data
PUTFDC
        ex af,af'
 LD   BC,#FB7E
PUTFD2 IN   A,(C)
        JP   P,PUTFD2
        ex af,af'
 inc c
        OUT  (C),A
        RET  
;
;Get data from FDC
;Ret = A=FDC data
GETFDC
 LD   BC,#FB7E
GETFD2 IN   A,(C)
 JP   P,GETFD2
 inc c
        IN   A,(C)
        RET  
;
;
;Track change
;a=nb piste
GOTOPIST
         PUSH AF
         LD   A,%00001111
         CALL PUTFDC
         LD   A,(FDCIDDR)
         CALL PUTFDC
         POP  AF
         CALL PUTFDC
;
         CALL WAITEND
;
         RET  
;
;
;Read sector.
;A=track
;B=ID sector
;RET=A=state.Carry=1=ok A=0=ok  1=disc missing  2=read fail
;3=file not found
;HL=Where new data should be loaded (LOADWHER)
READSECT
         LD   (RSPIST+1),A
         PUSH BC
         CALL GOTOPIST
;
         LD   A,%01000110
         CALL PUTFDC
         LD   A,(FDCIDDR)               ;ID drive
         CALL PUTFDC
RSPIST   LD   A,0                       ;track
         CALL PUTFDC
         XOR  A               ;head
         CALL PUTFDC
         POP  BC                        ;ID sect
         LD   A,B
         PUSH AF
         CALL PUTFDC
         LD   A,2                       ;size
         CALL PUTFDC
         POP  AF                        ;last sect to read
         CALL PUTFDC
         LD   A,#2A                     ;GAP
         CALL PUTFDC
         LD   A,#FF
         CALL PUTFDC
;
        LD   BC,#FB7E
 LD HL,(LOADWHER)
;
RSLOOP
        IN   A,(C)                     ;FDC ready for transf ?
        JP   P,RSLOOP
        AND  %00100000    ;FDC performing ?
        JR   Z,RSFIN
;
        INC  C
        IN   A,(C)
        LD   (HL),A
        INC  HL
;
        DEC  C
 jr RSLOOP
;
;Reading instr result
RSFIN
        CALL GETFDC
        LD   (ST0),A
        CALL GETFDC
        LD   (ST1),A
        CALL GETFDC
        LD   (ST2),A
        CALL GETFDC
        CALL GETFDC
        CALL GETFDC
        CALL GETFDC
;
;
;Test errors
;retour= Carry=1=ok a=0=ok  a=1=disc missing  2=read fail
;use ST0, ST1, ST2
         LD   A,(ST0)
         BIT  7,A
         JR   NZ,TESTEJEC               ;no disc
         BIT  3,A
         JR   NZ,TESTEJEC               ;no disc
         BIT  4,A
         JR   NZ,TESTFAIL               ;Read fail
;
         LD   A,(ST1)
         AND  %00110111
         JR   NZ,TESTFAIL
;
         LD   A,(ST2)
         AND  %00110000
         JR   NZ,TESTFAIL
;
TESTNOE
 XOR  A
 scf
 ret
TESTEJEC
 LD A,1
 or a
 ret
TESTFAIL
 LD A,2
 or a
 ret
ERRFNF
 LD A,3
 or a
 ret
;
;
;
;
FDCMOTOR defb 0   ;Drive motor (0-1)
FDCDRIVE defb 0   ;Drive used (0-3)
FDCHEAD defb 0   ;Head used (0-1)
FDCIDDR defb 0   ;Drive ID.
ST0 DEFB 0
ST1 DEFB 0
ST2 defb 0
LOADWHER defw 0  ;Where to load the file
;
;
 list
;*** End FDC code
 nolist
