;
; File: CC.PROM.FD.TEXT
; Date: 13-May-83
; By:   Ravi Luthra
;       Keith Ball
;

;
;       Fboot -- Floppy disk boot processing
;
Fboot   move.b  d0,CPbtslot.w       ;set boot slot number
        move.b  d0,CPosslot.w       ;set OS slot number
        clr.b   CPbtsrvr.w          ;set boot server number             0.7
        pea     FDblkIO             ;set boot disk blk i/o subr pointer
        move.l  (sp)+,CPblkio.w     ;*
        pea     FDsecIO             ;set boot disk sector i/o subr pointer
        move.l  (sp)+,CPdskio.w     ;*
        moveq   #0,d0               ;                                   0.7
        move.b  d0,CPossrvr.w       ;set OS server number               0.7
        move.w  d0,CPosblk+1.w      ;set OS volume block number         0.7
        move.b  d0,CPosdrv.w        ;set OS volume drive number         0.7
        bsr     FDI8sssd            ;set up floppy constants
        bsr     FDinit              ;initialize floppy drive
        blt.s   Fboot90             ;just return if error
                                    ;
Fboot1  move.l  #USRbase,a0         ;get block buffer pointer
        moveq   #0,d0               ;
        move.w  d0,d1               ;
        moveq   #DskRead,d5         ;get read block function code
                                    ;
        bsr.s   FDblkIO             ;read block 1 of boot code
        blt.s   Fboot90             ;just return if error
        bsr.s   FDblkIO             ;read block 2 of boot code
        blt.s   Fboot90             ;just return if error
        move.l  #USRbase,a0         ;get block buffer pointer
                                    ;
Fboot90 rts                         ;return

        page    ;FDblkIO
;
; PHILOSOPHY:  The user views floppy as a set of 512 byte blocks.
;              The driver then translates this block to track address, sector
;              address, side.
;              It then makes the necessary number of request to read sectors.
;              Partial sectors are not read or written, the excess is ignored.
;              Sector length of an Apple floppy is 256 bytes.
;
; RESTRICTION: Bytes per sector must be exact divisor of 512 (block size).
;              The block address must be less than (2**15)/bytes per sector,
;              so that when sector is formed, it fits in the D3.W.
;
; RESULTS OF SOME COMMANDS:
;
;  1) TRACK REG is incremented by 1 during STEPIN even
;     though there is a seek error because the TRACK adrs
;     requested exceeds the maximum track addres allowed
;
;  2) STEPOUT: the track register is not decremented below 0
;     after TRK00. The seek error bit is set.
;

;
; FDblkIO - Read/Write a Corvus floppy disk block subroutine
;
;       Enter:  A0.L - Buffer address
;               D0.W - Block number
;               D1.W - Drive number
;               D5.W - Read ($32) or Write ($33) command
;
;       Exit:   A0.L - Next free location in buffer
;               D0.W - Updated block number
;               D7.W - IORESULT
;
;       All other registers are preserved.
;
FDblkIO MOVEM.L D0-D6/A1-A6,-(SP)       ;
        MOVE.W  #BLKSZ,D2               ;BLOCK SIZE IN BYTES
        MOVE.W  D0,D3                   ;
        BSR     FDrdwr                  ;
        MOVEM.L (SP)+,D0-D6/A1-A6       ;restore registers
        ADDQ.W  #1,D0                   ;INC BASE BLOCK
        TST.B   D7                      ;set return condition code
        RTS                             ;return

        page    ;FDsctIO
;
; FDsctIO - Read/Write a Corvus floppy disk sector
;
;       Enter:  A0.L - Buffer address
;               D1.W - Bytes per sector (128 for single density)
;               D3.W - Track number
;               D4.W - Sector number
;               D5.W - Read ($32) or Write ($33) command
;
;       Exit:   D7.W - IORESULT
;
;       All other registers are preserved.
;
;DsecIO MOVEM.L D0-D6/A0-A6,-(SP)       ;save registers
;       BSR     FDgetadr                ;set address registers
;                                       ;A1 = ptr to device description info
;                                       ;A2 = ptr to slot controller registers
;                                       ;A3 = ptr to slot static RAM
;       CLR.L   D0                      ;
;       BSR     FDlcmd1                 ;turn on motor and setup controller
;       BSR     FDseek                  ;get to track
;       BNE.S   FDsio9                  ;if error, return
;       CMPI.W  #DskWrit,D5             ;only do write if cmd is a write
;       BNE.S   FDsio2                  ;else do a read
;       BSR     FDsecW                  ;
;       BRA.S   FDsio9                  ;
;                                       ;

FDsecIO CMPI.W  #DskWrit,D5             ;make sure cmd is a read cmd
        BNE.S   FDsio1                  ;it is
        BRA     FDEopcd                 ;it isn't, return error
                                        ;
FDsio1  MOVEM.L D0-D6/A0-A6,-(SP)       ;save registers
        BSR     FDgetadr                ;set address registers
                                        ;A1 = ptr to device description info
                                        ;A2 = ptr to slot controller registers
                                        ;A3 = ptr to slot static RAM
        CLR.L   D0                      ;
        BSR     FDlcmd1                 ;turn on motor and setup controller
        BSR     FDseek                  ;get to track
        BNE.S   FDsio9                  ;if error, return

FDsio2  BSR     FDsecR                  ;read sector specified by D4.W
                                        ;
FDsio9  BSR     FDmtrof                 ;turn off motor
        MOVEM.L (SP)+,D0-D6/A0-A6       ;restore registers
        TST.B   D7                      ;set return condition code
        RTS                             ;return

        page    ;floppy equates
SVLCMD  equ     0       ;SAVE OF LOCAL COMMAND
                        ;
NNMI1   equ     0       ;BIT POSITION FOR EACH STATUS BIT
NNMI2   equ     1       ;
NNMI3   equ     2       ;
NNMI4   equ     3       ;
                        ;
NIRQ1   equ     4       ;
NIRQ2   equ     5       ;
NIRQ3   equ     6       ;
NIRQ4   equ     7       ;
;
; Bytes per sector
;
BPS8ISD equ     128     ;Single density 8"
BPS8IDD equ     256     ;Double density 8"
BPS5ISD equ     256     ;Apple 5 1/4" floppy
;
; Sectors per track
;
SCPT8SD equ     26      ;Single density 8"
SCPT8DD equ     26      ;Double density 8"
SCPT5SD equ     16      ;Apple 5 1/4" floppy
;
; Tracks per side
;
TKPS8SD equ     77      ;Single density 8"
TKPS8DD equ     77      ;Double density 8"
TKPS5SD equ     35      ;Apple 5 1/4" floppy
;
; Number of blocks per disk
;
NBLK8SD equ     500     ;Single density 8" single sided
NBLK8DD equ     1001    ;Double density 8" single sided
NBLK5SD equ     280     ;Apple 5 1/4" floppy
;
; Error return codes
;
RGOOD     equ   0       ;disk accss successful
RBDBLK    equ   -1      ;Block requested is out of range
RBDUNT    equ   -2      ;bad unit number or driver not implemented
RBDOPCO   equ   -3      ;Requested unit I/O function is not valid
RHWRERR   equ   -4      ;Hardware error
RLOSTDEV  equ   -5      ;Lost device. i.e. device went offline
                        ;
RWRPROT   equ   -16     ;the unit is write protected
RSEEKERR  equ   -17     ;SEEK Error
RBUSY     equ   -18     ;device busy
RRNF      equ   -19     ;record not found - maybe disk is bad
RNOTRDY   equ   -20     ;device not ready
RERRUNOWN equ   -64     ;error origin unknown

        page    ;floppy hardware equates
;
; This section conatins the equates for Floppy Disk cont FD1793
; All references are w.r.t NDEV1AD in A2
; Prefix of 'L' means that this reference is to the 'LOCAL'
; logic on the disk controller board
; Prefix of FDC means that this referenc is to the Floppy disk controller
;
; Local disk controller board equates
;
LSTRR     equ   0       ;index to the local Status reg
LCMDR     equ   0       ;index to the local command reg
                        ;
LSDRQ     equ   0       ;BIT 0   =1 DRQ
LSINT     equ   1       ;INTERRUPT REQUEST
LS1SD2SD  equ   4       ;=0 if 2 sided , =1 if one sided
LS8INMIN  equ   5       ;=1 if 8 inch , =0 if min
LSDSKCHG  equ   6       ;=0 if disk changd, 1 if not
LSFMMFM   equ   7       ;=1 if sigl density =0 if double
;
; Command register equates
;
LCFLPSD1  equ   0       ;=0 if side 0 , =1 if side 1
LCDE0     equ   1       ;drive selct bit 0
LCDE1     equ   4       ;drive select bit 1
LCMOTOROF equ   5       ;=1 if motor to be turned off
LC8INMIN  equ   6       ;
LCFLP8IN  equ   6       ;=1 to select 8 in, =0 for 5 1/4
LCFMMFM   equ   7       ;=1 to select singl density , 0 for dbl

        page    ;
;
; Floppy disk controllers equates
;
FDCAD     equ   $10     ;Floppy disk controller base index
;
; address of the internal registers of FDC
;
FDCCMDR   equ   FDCAD+0 ;ADRS OF FDC COMMAMD REG
FDCSTRR   equ   FDCAD+0 ;ADRS OF FDC STATUS REG
FDCTRKR   equ   FDCAD+2 ;ADRS OF FDC TRACK REG
FDCSECR   equ   FDCAD+4 ;ADRS OF FDC SECTOR REG
FDCDATR   equ   FDCAD+6 ;ADRS OF FDC DATA REG
;
; Command code equates
;
CRESTORE  equ   0       ;0 0 0 0 H V R1 R0
CSEEK     equ   $10     ;0 0 0 1 h v r1 r0
CSTEP     equ   $20     ;0 0 1 U h v r1 r0
CSTEPIN   equ   $40     ;0 1 0 U h v r1 r0
CSTEPOUT  equ   $60     ;0 1 1 U h v r1 r0
;
; Type II commands
;
CRDSEC    equ   $80     ;1 0 0 m F2 E F1 0
CWRSEC    equ   $A0     ;1 0 1 m F2 E F1 0
;
;TYpe III commands
;
CRDAM     equ   $C0     ;1 1 0 0 0  E 0  0
CRDTRK    equ   $E0     ;1 1 1 0 0  E 0  0
CWRTRK    equ   $F0     ;1 1 1 1 0  E 0  0
CFRCINT   equ   $D0     ;1 1 0 1 I1 12 I3 I4
;
; FLAGS equates -- all flags have prefix of F
;
FHld      equ   $8      ;if =1 load head in the beginning
                        ;if =0  unload head in  beginning
FVerify   equ   $4      ;if =1 verify destination trk else not
FUpdttrk  equ   $10     ;if =1 update TRK reg after each STEP
FSTPRT3ms equ   $0      ;step rate = 3 milliseconds
FSTPRT6ms equ   $1      ;step rate = 6 milliseconds
FSTPRT10ms equ  $2      ;step rate = 10 milliseconds
FSTPRT15ms equ  $3      ;step rate = 15 milliseconds
                        ;
FMPS      equ   $10     ;M=1 if multiple sectors else =0
FDLY      equ   $4      ;E=1 if internal dly of 15 ms =0 no dly
FSDCPM    equ   $8      ;F2=0 compare with side 0,=1 with side 1
FSDCMPEN  equ   $2      ;F1=1 enable side compare, =0 disable cmp
                        ;
FINTRDY   equ   $1      ;not ready to ready
FINTNRDY  equ   $2      ;ready to not ready
FINTIDXP  equ   $4      ;interrupt on index pulse
FINTIMM   equ   $8      ;terminate command immediately and intrpt

        page    ;status register equates
;
; Status register equates -- all status reg bits have prefix of S
;
;name       bit position
;
SBUSY     equ   0       ;S0  busy
                        ;
SINDEX    equ   1       ;S1  index pulse encountered
SDRQ      equ   1       ;S1  data request
                        ;
STRK0     equ   2       ;S2  track 00
SDTOVER   equ   2       ;S2  data over run
SDTUNDR   equ   2       ;S2  data under run
                        ;
SCRCERR   equ   3       ;S3  crc error
                        ;
SSEEKERR  equ   4       ;S4  seek error
SRNF      equ   4       ;S4  record not found
                        ;
SHDLDD    equ   5       ;S5  head loaded
SRECTYP   equ   5       ;S5  record type
SWRFAULT  equ   5       ;S5  write fault
                        ;
SWRPROT   equ   6       ;S6  floppy write protected
                        ;
SNOTRDY   equ   7       ;S7  floppy not ready

        page    ;FDI....., FDinit
;
; FDI8sssd -- Set up constants for Corvus 8" single side single density
;
FDI8sssd
        bsr     FDgetadr                ;set address registers
                                        ;A1 = ptr to device description info
                                        ;A2 = ptr to slot controller registers
                                        ;A3 = ptr to slot static RAM
        move.w  #NBLK8SD,CPfdvsz(A1)    ;set device size in blocks
        move.w  #BPS8ISD,CPfbps(A1)     ;set bytes per sector
        move.b  #SCPT8SD,CPfspt(A1)     ;set sectors per track
        move.b  #TKPS8SD,CPftps(A1)     ;set tracks per side
        bra.s   FDI8ss                  ;set other values and return

;
; FDI8ssdd -- Set up constants for Corvus 8" single side double density
;
FDI8ssdd
        bsr     FDgetadr                ;set address registers
                                        ;A1 = ptr to device description info
                                        ;A2 = ptr to slot controller registers
                                        ;A3 = ptr to slot static RAM
        move.w  #NBLK8DD,CPfdvsz(A1)    ;set device size in blocks
        move.w  #BPS8IDD,CPfbps(A1)     ;set bytes per sector
        move.b  #SCPT8DD,CPfspt(A1)     ;set sectors per track
        move.b  #TKPS8DD,CPftps(A1)     ;set tracks per side
FDI8ss  move.b  #1,CPfspd(A1)           ;set sides per disk
        move.b  #1,CPfofst(A1)          ;set first track offset
        rts                             ;return

;
; FDinit -- Initialize Corvus floppy disk drive
;
FDinit  BSR     FDgetadr                ;set address registers
                                        ;A1 = ptr to device description info
                                        ;A2 = ptr to slot controller registers
                                        ;A3 = ptr to slot static RAM
        CLR.L   D0                      ;
        MOVEQ   #1,D1                   ;A FAKE SECTOR LENGTH
        BSR.S   FDlcmd1                 ;turn on motor and setup controller
        BSR     FDrst                   ;restore to track 0
        BSR.S   FDmtrof                 ;turn motor off
        TST.B   D7                      ;set return condition code
        RTS                             ;return

        page    ;FDmtrof, FDlcmd
;
;  D0.W  -- FREE
;  D1.W  -- FREE
;  D2.W  -- BYTE CNT
;  D3.W  -- BASE BLK  ADRS
;  D4.W  -- FREE
;  D5.W  -- USER CMD
;  D6.W  -- FREE
;
;  A0.L  -- USER BUFFER ADDRESS
;  A1.L  -- DEVICE DESCRIPTION AREA BASE ADDRESS
;  A2.L  -- FLOPPY CONTROLLER BASE ADDRESS
;  A3.L  -- STATIC RAM BASE ADDRESS
;
;
; FDmtrof -- Turn motor off
;
FDmtrof move.b  SVLCMD(A3),D4           ;get current local command
        bset    #LCMOTOROF,D4           ;set motor off flag
        move.b  D4,LCMDR(A2)            ;move command to command register
        move.b  D4,SVLCMD(A3)           ;save current local command
        rts                             ;return

;
; FDlcmd -- GET THE LOCAL COMMAND FOR THIS DRIVE INTO REGISTER D0.B
;           RETURNS WITH D7 CLEAR LONG
;
FDlcmd  bsr     FDclcTS         ;Calc first side trk sec
        ;
        ; form a local command in D0
        ; Entry used for Read/Write a sector
        ;
FDlcmd1 bclr    #LCMOTOROF,D0   ;clear motor off bit
        bset    #LCFLP8IN,d0    ;indicate 8 inch flp
        bset    #LCFMMFM,d0     ;indicate 8 inch flp
        move.b  CPosdrv(a1),d7  ;sel drive
        ror.w   #1,d7           ;note DE0 is B0
        lsl.b   #2,d7           ;DE1 is B4
        rol.w   #2,d7           ;
        or.b    d7,d0           ;set into d0
        move.b  d0,SVLCMD(a3)   ;save then command
        move.b  d0,LCMDR(a2)    ;set local command register
        clr.l   d7              ;clear error register
        rts                     ;return

        page    ;FDrdwr
FDrdwr  BSR     FDgetadr        ;set address registers
                                ;A1 = pointer to device description info
                                ;A2 = pointer to slot controller registers
                                ;A3 = pointer to slot static RAM
        TST.W   D3              ;test base block
        BMI     FDEblck         ;jump if first blk rqstd is invalid
        cmp.w   CPfdvsz(A1),d3  ;is it in limit
        bge     FDEblck         ;jump final block exceeds max
        BSR.S   FDlcmd          ;set local command register

;----------------------------------------------------------------
;  D0.W  -- LOCAL COMMAND
;  D1.W  -- BYTES PER SEC
;  D2.W  -- WORD CNT
;  D3.W  -- TRACK ADDRESS
;  D4.W  -- SECTOR ADDRESS
;  D5.W  -- USER COMMAND
;  D6.W  -- FREE
;----------------------------------------------------------------
; READS/WRITES ONLY COMPLETE SECTORS
; For the rest of the code:
;         A0       points to the user buffer address
;         A1       points to the beginning of the device
;                  table entry for this volume in D0 at the entry
;         A2       Contains the NDEVICE address of the slot
;                  specified in the device table for this Volume
;         A3       BASE ADDRESS OF LOCAL STATIC RAM
;----------------------------------------------------------------

        bsr     FDseek          ;seek the desired track
        bne.s   FDrdwr9         ;if error, return
                                ;
FDrdwr1 sub.w   d1,d2           ;
        bmi.s   FDrdwr9         ;return if no more sectors to process
        bsr.s   FDsecRW         ;process sector
        tst.b   d7              ;d7 contains result code
        bne.s   FDrdwr9         ;if error, return
        bsr     FDincTS         ;
        BNE.S   FDrdwr9         ;TIMED OUT ERROR
        bra.s   FDrdwr1         ;process next sector
                                ;
FDrdwr9 bsr     FDmtrof         ;turn off motor
        rts                     ;return

        page    ;FDsecRW, FDsecR
;
; FDsecRW -- Read or write a sector of data to the floppy
;            It transfer the data to/from the adrs in A0
;            from / to the floppy
;
;       Enter:  D5 - DskRead or DskWrit
;
FDsecRW                          ;fall thru to FDsecR
;        cmp.w   #DskWrit,D5     ;see if it is a Unit write
;        beq.s   FDscRW1
;        bsr.s   FDsecR
;        bra.s   FDscRW9
;FDscRW1 bsr.s   FDsecW
;FDscRW9 rts

;
; FDsecR -- Read one sector of data
;
;       Enter:  bytes per sec --->  D1.w
;               sector adrs  -----> D4.w
;               buffer adrs  -----> A0
;               floppy must be poitioned on desired track
;
;       Exit:   OS result code --->  D7
;               data   to the adrs pointed by A0
;
FDrcRd  equ     4               ;read sector retry count
FDrcDOr equ     4               ;data overrun retry count
                                ;
FDsecR  movem.l d5-d6,-(SP)     ;save
        move.w  #FDrcRd,d5      ;get read sector retry count
        move.l  a0,a4           ;save user buf ptr
                                ;
FDsecR1 move.w  #FDrcDOr,d6     ;get data overrun retry count
                                ;
FDsecR2 move.l  a4,a0           ;get user buf adrs
        BSR     FDwRdy          ;WAIT FOR READY OR TIMED OUT
        BNE.S   FDsecR9         ;TIMED OUT ERR
        BSR     FDccRd          ;
        btst    #SDTOVER,d7     ;is ther  data overrun
        dbeq    d6,FDsecR2      ;data over run, try again.
        btst    #SCRCERR,d7     ;is ther crc error
        DBEQ    d5,FDsecR1      ; DO UNTIL (no crc error)
                                ;   or (no more retries left)
                                ;
FDsecR3 BSR     FDrdSta         ;check read status
        beq.S   FDsecR9         ;
        move.l  a4,a0           ;
                                ;
FDsecR9 movem.l (sp)+,d5-d6     ;
        tst.b   d7              ;d7 contains result code
        rts                     ;return

        page    ;FDsecW
;
; FDsecW -- Write one sector of data
;
;       Enter:  bytes per sec --->  D1.w
;               sector adrs  -----> D4.w
;               buffer adrs  -----> A0
;               floppy must be poitioned on desired track
;
;        Exit:  OS result code --->  D7
;               data   to the adrs pointed by A0
;
;FDrcWr  equ     4               ;write sector retry count
;FDrcDOw equ     4               ;data overrun retry count
;                                ;
;FDsecW  movem.l d5-d6,-(SP)     ;save registers
;        move.w  #FDrcWr,d5      ;get write retry count
;        move.l  a0,a4           ;save user buf ptr
;                                ;
;FDsecW1 move.w  #FDrcDOw,d6     ;get data overrun retry count
;                                ;
;FDsecW2 move.l  a4,a0           ;get user buf adrs
;        BSR     FDwRdy          ;WAIT FOR READY OR TIMED OUT
;        BNE.S   FDsecW9         ;TIMED OUT ERR
;        BSR     FDccWr          ;
;        btst    #SDTOVER,d7     ;data overrun?
;        dbeq    d6,FDsecW2      ;yes, try again
;        btst    #SCRCERR,d7     ;CRC error?
;        dbeq    d5,FDsecW1      ;yes, try again
;                                ;
;        BSR     FDwrSta         ;check write status
;        beq.S   FDsecW9         ;if no error, return
;        move.l  a4,a0           ;
;                                ;
;FDsecW9 movem.l (sp)+,d5-d6     ;restore registers
;        tst.b   d7              ;d7 contains result code
;        rts                     ;return

        page    ;FDccRd
; ***** TYPE II COMMANDS *****

;
; FDccRd -- Read one sector of data
;
;       Enter:  bytes per sec --->  D1.w
;               sector adrs  -----> D4.w
;               buffer adrs  -----> A0
;               floppy must be positioned on desired track
;
;       Exit:   status   ----->  D7
;               data   to the adrs pointed by A0
;
FDccRd  move.w  d1,-(SP)                ;save
        subq.w  #1,d1                   ;byte count
        move.w  sr,-(SP)                ;
        ori.w   #$0700,sr               ;disable interrupts
        move.b  d4,FDCSECR(A2)          ;
        move.b  #CRDSEC,FDCCMDR(A2)     ;issue command
        move.w  #25,d7                  ;wait at least 28 micro-second
FDccRd1 dbf     d7,FDccRd1              ;
                                        ;
FDccRd2 btst    #SBUSY,FDCSTRR(A2)      ;see if the ctlr is busy
        beq.S   FDccRd2                 ;jump if not busy
        ;
        ; ***** TIME CRITICAL LOOP
        ;
FDccRd3 move.b  LSTRR(A2),D7            ;read status
        btst    #LSDRQ,d7               ;is DRQ there
        bne.s   FDccRd5                 ;yes , jump
                                        ;
FDccRd4 btst    #LSINT,D7               ;is FDC done
        beq.s   FDccRd3                 ;no, jump
        bra.s   FDccRd6                 ;ctlr terminated too soon
                                        ;
FDccRd5 move.b  FDCDATR(A2),(a0)+       ;get a byte from FDC
        dbf     d1,FDccRd3              ;read the remaining bytes
        ;
        ; a complete sector has been read.
        ;
        bsr      FDnRdy                 ;
                                        ;
FDccRd6 move.b   FDCSTRR(A2),d7         ;read the status
        move.w   (sp)+,sr               ;restore SR
        move.w   (SP)+,d1
        rts

        page    ;FDccWr
;
; FDccWr -- Write one sector of data
;
;       Enter:  bytes per sec --->  D1.w
;               sector adrs  -----> D4.w
;               buffer adrs  -----> A0
;               floppy must be poitioned on desired track
;
;       Exit:   status   ----->  D7
;               data   to the adrs pointed by A0
;
;FDccWr  move.w  d1,-(SP)                ;save
;        subq.w  #1,d1                   ;byte count
;        move.w  sr,-(SP)                ;
;        ori.w   #$0700,sr               ;disable interrupts
;        BSR.S   FDccWr1                 ;CALL time critical FDccWr PART
;        bsr     FDnRdy                  ;
;        move.b  FDCSTRR(A2),d7          ;read the status
;        move.w  (sp)+,sr                ;restore SR
;        move.w  (SP)+,d1                ;
;        rts                             ;return
;                                        ;
;                                        ;
;FDccWr1 move.b  d4,FDCSECR(A2)          ;
;        move.b  #CWRSEC,FDCCMDR(A2)     ;issue command
;                                        ;
;        move.w  #25,d7                  ;wait at least 28 micro-second
;FDccWr2 dbf     d7,FDccWr2              ;
;                                        ;
;FDccWr3 btst    #SBUSY,FDCSTRR(A2)      ;
;        beq.s   FDccWr3                 ;
;        ;
;        ; ***** TIME CRITICAL LOOP
;        ;
;FDccWr4 move.b  LSTRR(A2),D7            ;FDCSTRR(A2),d7 ;read status
;        btst    #LSDRQ,d7               ;is DRQ there
;        bne.s   FDccWr6                 ;yes , jump
;                                        ;
;FDccWr5 btst    #LSINT,D7               ;is FDC done
;        beq.s   FDccWr4                 ;no , jump
;        rts                             ;terminated too soon
;                                        ;
;FDccWr6 move.b  (a0)+,FDCDATR(A2)       ;move a byte to FDC
;        dbf     d1,FDccWr4              ;write the reamining bytes
;        RTS                             ;return

        page    ;FDgetadr
;
; FDgetadr -- Get pointers to device description info, controller registers,
;             and static RAM for current slot
;
;       Exit:   A1 = pointer to device description info
;               A2 = pointer to controller registers for slot
;               A3 = pointer to static RAM for slot (CPosslot)
;
FDgetadr
        movea.l #0,A1           ;get pointer to device description info
        move.l  #NDEV1AD,A2     ;get pointer to controller registers
        move.b  CPosslot(a1),d7 ;*
        ext.w   d7              ;*
        mulu.w  #DEVADOFST,d7   ;*
        adda.l  d7,a2           ;*
        lea     CPsl1ram.w,A3   ;get pointer to static RAM
        move.b  CPosslot(a1),d7 ;*
        ext.w   d7              ;*
        subq.w  #1,d7           ;*
        mulu    #$100,d7        ;*
        adda.l  d7,A3           ;*
        rts                     ;return

        page    ;FDclcTS
;
; FDclcTS -- calculate the Side, Track address and sector
;            address for the First block requested by the user
;
;       Enter:  A1      - device table address
;               D3      - block address
;
;       Exit:   D0.bit  - side flag
;               D3.w    - track address
;               D4.w    - sector address
;
FDclcTS clr.l   d0              ;
        move.w  CPfbps(A1),D1   ;get bytes per sector
        ext.l   d3              ;clear the upper 16 bits of d3
        move.l  #BLKSZ,d7       ;
        divu    d1,d7           ;
        mulu    d7,d3           ;absolute sector adrs to d3
        move.l  d3,d7           ;
        clr.w   d4              ;make sure that upper byte is 00
        move.b  CPfspt(A1),d4   ;
        divu    d4,d7           ;
        move.w  d7,d3           ;absolute track adrs to d3
        swap    d7              ;
        move.b  CPfofst(a1),d4  ;get first sector offset
        ext.w   d4              ;*
        add.w   d7,d4           ;get sector address
; ----  bclr    #LCFLPSD1,d0    ;select side 0          (already 0)
        move.b  CPftps(A1),d7   ;get tracks per side
        ext.w   d7              ;*
        cmp.w   d7,d3           ;is track on side 0?
        blt.s   FDclcT9         ;yes, return
        cmpi.b  #1,CPfspd(a1)   ;is there a side 1?
        beq.s   FDclcT8         ;no, report error
        bset    #LCFLPSD1,D0    ;select side 1
        sub.w   d7,d3           ;update track address
        cmp.w   d7,d3           ;is track on side 1?
        blt.s   FDclcT9         ;yes, return
                                ;
FDclcT8 bra     FDEblck         ;indicate block number error
                                ;
FDclcT9 clr.w   d7              ;indicate no error
        rts                     ;return

        page    ;FDincTS
;
; FDincTS -- update the sector address by one. If it was the last
;            sector on the track then update the Track adrs by
;            one. If it was the last track then update the side
;            in the Local command reg and D0 and restore track to 0.
;
;       Exit:   NE - error and D7 has error code
;               EQ - successful update D7 = 0
;
FDincTS addq.w  #1,d4           ;increment sector number
        move.b  CPfspt(A1),d7   ;get last sector number + 1
        add.b   CPfofst(A1),d7  ;*
        cmp.b   d7,d4           ;are we past last sector?
        bge.s   FDincT1         ;yes, go to next track
        clr.w   d7              ;show successful
        bra.s   FDincT9         ;return
                                ;
FDincT1 move.b  CPfofst(A1),d4  ;reset sector number
        ext.w   D4              ;*
        move.b  CPftps(A1),d7   ;get tracks per side
; ----  cmpi.b  #DTa5,CPftyp(a1);is this an Apple floppy drive?        0.7
; ----  beq.s   FDincT5         ;yes, process it                       0.7
        ;
        ; Corvus 8" floppy drive
        ;
        cmp.b   d7,d3           ;are we past last track on side?
        bge.s   FDincT2         ;yes, go to next side
        addq.w  #1,d3           ;increment track number
        bsr.s   FDwRdy          ;wait for ready or timeout
        bne.s   FDincT9         ;return if timeout error
        bsr     FDccSin         ;step in 1 track
        bsr     FDskSta         ;check seek status
        bra.s   FDincT9         ;return
                                ;
FDincT2 clr.w   d3              ;reset track number
        bset    #LCFLPSD1,D0    ;Select side 1
        move.b  D0,LCMDR(A2)    ;*
        bsr     FDrst           ;restore to track 0
; ----  bra.s   FDincT9         ;return                                0.7
; ----  ;                                                              0.7
; ----  ; Apple 5" floppy drive                                        0.7
; ----  ;                                                              0.7
;DincT5 cmp.b   d7,d3           ;are we past last track on side?       0.7
; ----  bge     FDEblck         ;yes, report error                     0.7
; ----  addq.w  #1,d3           ;increment track number                0.7
; ----  bsr     ADccSin         ;step in 1 track                       0.7
                                ;
FDincT9 tst.w   d7              ;set return condition codes
        rts                     ;return

        page    ;FDwRdy
;
; FDwRdy --  WAIT UNTIL FDC SAYS DRIVE IS READY OR
;            TIME OUT (NOT MORE THAN 1 SECOND)
;
;       Exit:   NE = timed out D7 has error result
;               EQ = ready (D7 = 0)
;
FDtmoHi equ     4                       ;SHOULD BE AT LEAST 1 SECOND
FDtmoLo equ     $7FFF                   ;*
                                        ;
FDwRdy  CLR.L   D7                      ;
        MOVEM.W D5-D6,-(SP)             ;SAVE D6 AND D5
        MOVE.W  #FDtmoLo,D5             ;
        MOVE.W  #FDtmoHi,D6             ;
                                        ;
FDwRdy1 BTST    #SNOTRDY,FDCSTRR(A2)    ;IS FLOPPY READY
        DBEQ    D5,FDwRdy1              ;DO UNTIL (FLOPPY READY) OR (TIME OUT)
        DBEQ    D6,FDwRdy1              ;
        BEQ.S   FDwRdy9                 ;DIDN'T TIME OUT
        MOVE.W  #RNOTRDY,D7             ;
                                        ;
FDwRdy9 MOVEM.W (SP)+,D5-D6             ;
        TST.W   D7                      ;SET CONDITION CODES - NE MEANS ERROR
        RTS                             ;return

        page    ;FDseek
;
; FDseek --
;
; It is assumed that TRACK REG contains the number of the track
; of the current position of the read write Head.
;
;       Enter:  D3.W - Seek track address
;
FDrcSk  equ     4               ;seek retry count
                                ;
FDseek  BSR.S   FDwRdy          ;WAIT FOR READY OR TIMED OUT
        BNE.S   FDseek9         ;TIMED OUT ERR
        BSR     FDccSk          ;
        BSR     FDskSta         ;check seek status
        BEQ.S   FDseek9         ;there is NO error
        move.w  d5,-(sp)        ;save d5
        move.w  #FDrcSk,D5      ;
                                ;
FDseek1 BSR.S   FDwRdy          ;WAIT FOR READY OR TIMED OUT
        BNE.S   FDseek8         ;TIMED OUT ERR
        BSR.S   FDccRst         ;
        BSR.S   FDwRdy          ;WAIT FOR READY OR TIMED OUT
        BNE.S   FDseek8         ;TIMED OUT ERR
        BSR.S   FDccSk          ;
        btst    #sseekerr,d7    ;
        DBEQ    d5,FDseek1      ;try until no seek error or
                                ;no more retries
        BSR     FDskSta         ;check seek status
                                ;
FDseek8 move.w  (sp)+,d5        ;
                                ;
FDseek9 TST.B   D7              ;set return condition code
        RTS                     ;return

        page    ;FDrstW, FDrst
;
; FDrstW -- Restore the floppy to track 0
;           It exits when it has successfully restored the floppy to
;           track 0 or when the retry count has exhausted.
;           Then it calls the FDswSta routine to analyse status.
;           Note W in FDswSta. It looks at WRprot bit of FDCSTRR.
;
FDrstW  movem.l a6/d6,-(sp)     ;
        lea     FDswSta,a6      ;
        bra.s   FDrst0          ;

;
; FDrst -- same as FDrstW except no W there.
;          It does not look at Write protect status bit in FDCSTRR.
;
FDrst   movem.l a6/d6,-(sp)     ;
        lea     FDskSta,a6      ;
                                ;
FDrst0  move.w  #4,d6           ;
                                ;
FDrst1  BSR.S   FDwRdy          ;WAIT FOR READY OR TIMED OUT
        BNE.S   FDrst2          ;TIMED OUT ERR
        bsr.s   FDccRst         ;
        jsr     (a6)            ;
        dbeq    d6,FDrst1       ;do until (successful) or (tried enough)
                                ;
FDrst2  movem.l (sp)+,a6/d6     ;
        rts                     ;return

        page    ;FDcc...
;
; ***** TYPE I COMMANDS *****
;
FDCrst   equ    CRESTORE+FSTPRT15ms+FVERIFY
FDCstp   equ    CSTEP+FSTPRT6ms+FVERIFY+FUpdttrk
FDCstpIn equ    CSTEPIN+FSTPRT6ms+FVERIFY+FUpdttrk
FDCstpOt equ    CSTEPOUT+FSTPRT6ms+FVERIFY+FUpdttrk
FDCseek  equ    CSEEK+FSTPRT6ms+FVERIFY
;
; FDccRst -- bring the floppy back to track 00
;            Then set the FDCTRKR = 0
;            Stepping pulses are given at the rate specified in cmd
;
FDccRst move.b  #FDCrst,FDCCMDR(A2)     ;issue command
        bra.s   FDnRdy                  ;wait for not ready
;
; FDccStp -- FDCTRKR+/-1 --> FDCTRKR
;
FDccStp move.b  #FDCstp,FDCCMDR(A2)     ;issue command
        bra.s   FDnRdy                  ;wait for not ready
;
; FDccSin -- FDCTRKR+1 --> FDCTRKR
;
FDccSin move.b  #FDCstpIn,FDCCMDR(A2)   ;issue command
        bra.s   FDnRdy                  ;wait for not ready
;
; FDccSot -- FDCTRKR-1 --> FDCTRKR
;
FDccSot move.b  #FDCstpOt,FDCCMDR(A2)   ;issue command
        bra.s   FDnRdy                  ;wait for not ready
;
; FDccSk -- issue a seek command.  If there is a seek error,
;           flip the density flag in D0 and try again
;
FDccSk  move.w  d5,-(sp)                ;save d5
        move.b  D3,FDCDATR(A2)          ;load the desired TRACK adrs
        moveq   #2,d5                   ;
                                        ;
FDccSk1 move.b  #FDCseek,FDCCMDR(A2)    ;issue command
        bsr.s   FDnRdy                  ;wait for not ready
; ----  btst    #sseekerr,d7            ;
; ----  beq     FDccSk2                 ;no seek error
; ----  bchg    #LSFMMFM,d7             ;flip the density bit
; ----  dbf     d5,FDccSk1              ; $$$ WE MAY HAVE TO FLIP $$$
                                        ;
FDccSk2 move.w  (sp)+,d5                ;get back d5
        rts                             ;return

        page    ;FDnRdy
;
; FDnRdy --  WAIT UNTIL FDC SAYS DRIVE IS NOT BUSY OR TIME OUT
;
;       Exit:   D7 = controller status register (FDCSTRR)
;
FDnRdy  movem.w d5-D6,-(SP)             ;
        move.w  #FDtmoLo,d6             ;
        move.w  #2,d5                   ; add 3*$8000 iterations
                                        ;
FDnRdy1 btst    #LSINT,LSTRR(a2)        ;is it busy
        dbNE    d6,FDnRdy1              ;DO UNTIL (not busy) or (no more retries)
        dbNE    d5,FDnRdy1              ;DO UNTIL (not busy) or (no more retries)
                                        ;
FDnRdy2 movem.w (SP)+,d5-d6             ;
        MOVE.B  FDCSTRR(A2),D7          ;GET CONTROLLER STATUS
        RTS                             ;return

        page    ;check status
;
; Check status subroutines
;
;       Exit:   D7 - IORESULT code
;
FDrdSta move.b  FDCSTRR(A2),d7  ;read the status
;        bra.s   FDrwSta         ;
;                                ;
;FDwrSta move.b  FDCSTRR(A2),d7  ;read the status
;        btst    #SWRPROT,d7     ;
;        bon.s   FDEprot         ;
;        btst    #SWRFAULT,d7    ;
;        bon.s   FDEherr         ;
                                ;
FDrwSta btst    #SCRCERR,d7     ;
        bon.s   FDEcrc          ;
        btst    #SRNF,d7        ;
        bon.s   FDErnf          ;
                                ;
FDrwSt1 btst    #SBUSY,d7       ;
        bon.s   FDEbusy         ;
        btst    #SNOTRDY,d7     ;
        bon.s   FDEnrdy         ;
        bra.s   FDokSta         ;no error, return
                                ;
FDswSta move.b  FDCSTRR(a2),d7  ;
        btst    #SWRPROT,d7     ;
        bon.s   FDEprot         ;
        bra.s   FDskSt1         ;
                                ;
FDskSta move.b  FDCSTRR(a2),d7  ;
                                ;
FDskSt1 btst    #SSEEKERR,d7    ;seek error?
        bon.s   FDEseek         ;SEEK ERROR IN RSLT CODE
        btst    #SCRCERR,d7     ;
        bon.s   FDEcrc          ;
        btst    #sbusy,d7       ;
        bon.s   FDEbusy         ;HARDWARE ERROR
        btst    #SNOTRDY,d7     ;
        bon.s   FDEnrdy         ;
                                ;
FDokSta clr.w   d7              ;indicate no error
                                ;
FDerSta tst.w   d7              ;set return condition code
        rts                     ;return

        page    ;set error status
FDEcrc                          ;error -- CRC
FDEblck move.w  #RBDBLK,d7      ;error -- invalid block number
        bra.s   FDerSta         ;set condition code and return
                                ;
FDEunit move.w  #RBDUNT,d7      ;error -- invalid unit number
        bra.s   FDerSta         ;set condition code and return
                                ;
FDEopcd move.w  #RBDOPCO,d7     ;error -- invalid op code
        bra.s   FDerSta         ;set condition code and return
                                ;
FDEherr move.w  #RHWRERR,d7     ;error -- hardware
        bra.s   FDerSta         ;set condition code and return
                                ;
FDEprot move.w  #RWRPROT,d7     ;error -- write protect
        bra.s   FDerSta         ;set condition code and return
                                ;
FDEseek move.w  #RSEEKERR,d7    ;error -- seek
        bra.s   FDerSta         ;set condition code and return
                                ;
FDErnf  move.w  #RRNF,d7        ;error -- record (sector) not found
        bra.s   FDerSta         ;set condition code and return
                                ;
FDEbusy move.b  #CFRCINT+FINTIMM,FDCCMDR(A2)
        move.w  #RBUSY,D7       ;error -- busy
        bra.s   FDerSta         ;set condition code and return
                                ;
FDEnrdy move.w  #RNOTRDY,d7     ;error -- not ready
        bra.s   FDerSta         ;set condition code and return

