           lib     environment
           lib     bfhdr
           lib     dtab
           lib     macdefs
           lib     hardware
           data
           ttl     Floppy Disk Drivers (SBC)
           pag
           name    flopdrvr
           global  flopopn,flopcls,flopio,flopint
           global  fchop,fchcl,fchsp,fchio,fchrd,fchwr
           global  fchgb,fchcn2,frechbf
           global  dselint

*
* This file contains the drivers for the SWTPC
* SBC dual density floppy disk controller.
*
*   Modified 12/28/83 for LS138 binary drive select j.d.
*
* driver constants
*


SECLEN     equ     512                 sector length
RWOK       equ     %11011000           read write status mask
RNFD       equ     %00010000           record not found error
MAXTRK     equ     76                  maximum track number allowed
RDCMND     equ     $88                 read block command
WTCMND     equ     $A8                 write block command
DWTCMD     equ     $AC                 write block with head settle
SKCMND     equ     $18                 seek command
RSCMND     equ     $08                 restore command
WTTCMD     equ     $F4                 write track command
FICMND     equ     $D0                 force interrupt command
RDMSCM     equ     $98                 read multiple command (swap in)
WTMSCM     equ     $B8                 write multiple command (swap out)
DWTMSC     equ     $BC                 write multiple with head settle
SIDE1      equ     $02                 side 1 in read/write commands



           pag

*
* driver variable storage
*

flopdrv    fcb     0                   current drive selected
flophdr    fcb     0                   hardware compat drive number
floptrk    fdb     0,0                 track table
flopsts    fdb     0,0                 side table
flopstd    fdb     0,0                 density table
flopden    fcb     0                   density flag
flopsid    fcb     0                   side flag
cmd_side   fcb     0                   side bit in WD command
dmasd      fcb     0                   current side select
floptmp    fdb     0                   temp space for open
dmswop     fcb     0                   swap operation (read or write)
dmswdr     fcb     0                   swap direction for controller
dmswpt     fdb     0                   swap table pointer
flopskf    fcb     0                   seek flag
flopopt    fdb     0,0                 flop open table
BDtable    fdb     0                   Block Device Table address
did_write  fcb     0                   Last I/O operation was a write
last_driv  fcb     0                   Last partial pattern to ds latch
wd_cnt     fcb     0                   wait for drive ready counter
WD_MAX     equ     10                  number of 0.5 second time-outs
cmdsav     fcb     0                   SAVE AREA FOR FDC COMMAND
*                                      FOR LOST DATA PROBLEM (TAS 11/6/84)


           pag

*
* flopopn
*
* Open FLOP device.  This guy reads in the sir
* block (1) and sets up the density and side info.
*

flopopn
           pshs    d                   save device number
           subb    #FLOPminor          compute relative drive #
           ldx     #flopopt            point to open table
           lda     b,x                 get this guys entry
           lbne    flopop3             if != 0, already open
           ldd     0,s                 reset device number
           jsr     fchop               do char open stuff
           ldd     0,s                 get dev number
           bsr     floprbo             read block one (sir)
           beq     flopop4             error?
           clr     uerror              reset error status
           jsr     freebf              free the buffer
           ldx     #flopstd            point to density table
           ldd     0,s                 get device number
           subb    #FLOPminor          compute relative drive #
           inc     b,x                 set to double density
           ldd     0,s                 restore device number
           bsr     floprbo             read sir again
           beq     flopop4             error?
           lda     #EIO                set io error
           sta     uerror
           lbsr    freebf              free the buffer
           ldx     #flopopt            point to open table
           ldd     0,s                 get device number
           subb    #FLOPminor          compute relative drive #
           clr     b,x                 clear status
flopop3    puls    d,pc                return
flopop4    pshs    y                   save buffer
           ldx     0,s                 get buffer
           ldy     #floptmp            point to data block
           ldu     #sdenf              set density offset in sir
           ldd     #2                  set byte count to 2
           jsr     cpybts              get density & side info
           ldd     2,s                 get device number
           subb    #FLOPminor          compute relative drive #
           ldx     #flopsts            point to side table
           lda     floptmp+1           get side data
           sta     b,x                 set in table
           leax    4,x                 bump to density table
           lda     floptmp             get density info
           sta     b,x                 set in table
           puls    y                   get buffer
           jsr     freebf              free the buffer
           puls    d,pc                return

*
* read sir
*

floprbo    ldx     #1                  set block 1
           ldy     #0
           lda     #FLOPmajor
           jsr     rdbuf               read in the block
           lda     bfflag,y            get flags
           bita    #BFERR              error?
           rts                         return

*
* flopcls
*
* Close FLOP device.  Nothing to do right now.
*

flopcls
           subb    #FLOPminor          compute relative drive #
           ldx     #flopopt            point to open table
           clr     b,x                 clear open status
           rts                         return

           pag

*
* flopio
*
* Start dmaf3 executing a requested operation.
*

flopio     stx     BDtable             save Block Device Table address
flopio2    inc     flopdt+dtbusy       set busy status
           lda     bfdvn+1,y           get device number
           clrb
           suba    #FLOPminor          compute relative device #
           cmpa    flopdrv             is it the current drive?
           bne     flopcd              if not - change drives
           ldx     #flopsts            point to side table
           leax    a,x                 point to entry
           lda     0,x                 get side
           sta     flopsid             set flag
           lda     4,x                 get density
           sta     flopden             set flag
           bra     flopsk              go seek

           pag

*
* flopcd
*
* Change drives.  Select the drive specified in
* the A accumulator.  This routine is entered by
* falling through from above.
*

flopcd     bsr     flopftr             find the track number
           sta     flopdrv             save the drive number
           ldb     TRK1797             get track from wd
           stb     0,x                 save in table
           bsr     flopftr             find entry
           ldb     0,x                 get old track number
           stb     TRK1797             set into wd
           ldb     4,x                 get side info
           stb     flopsid
           ldb     8,x                 get density info
           stb     flopden
           ldb     flopdrv             get the drive number back
flopcd4    stb     flophdr             save hardware drive number
           ldd     #20                 delay some here
flopcd5    subd    #1                  before drive change
           bne     flopcd5
           ldb     ORA29               toggle the head load timer
           andb    #($FF-hltogg)       by bring the via line low for a sec
           orb     #fdmotor+P09229     insure motor on
           stb     ORA29
           orb     #hltogg             then bring it back high
           stb     ORA29
           ldb     flophdr             reset drive number
           lbsr    drvb
           bra     flopsk              go do seek

*
* flopftr
*
* Find old value of the track register in wd.
* Also set the new value since changing drives.
*

flopftr    ldx     #floptrk            point to track table
           ldb     flopdrv             get drive number
           abx                         point to entry
           rts                         return

           pag

*
* flopsk
*
* Seek the head to the desired track.  Calculate
* the track and sector numbers from the block
* number passed in the transaction record.  The
* track is blkno>>3, and the sector is (blkno&3)+1.
* This is step one of the drivers and is indicated
* by the dtbusy flag set to 1.
*

flopsk
           clrb                        set status
           tst     bfblch,y            check high block number
           lbne    floper2             show error if set
           ldd     bfxfc,y             get xfr count
           cmpd    #512                doing block transfer?
           beq     flopsk2
           cmpd    #16                 is it a swap?
           lbhi    dmcsk               if not - do character
flopsk2    ldd     bfblck,y            get low block number
           tst     flopden             double density?
           bne     flopdd              if so - go handle it
           pshs    b
           lsra                        divide by 16
           rorb                        which is sectors per track
           lsra
           rorb
           lsra
           rorb                        all done now
           tsta                        check track too big
           beq     flopsk3
           puls    b                   clean up stack
           bra     flopsk8             go report error
flopsk3    tfr     b,a                 put track number in a
           puls    b                   get original
           andb    #7                  mask sector number
           incb                        adjust (no sector 0)
           clr     dmasd               clear side flag
           tst     flopsid             is this drive double sided?
           beq     flopsk4
           lsra                        adjust track number
           bcc     flopsk4             switch sides?
           addb    #8                  adjust sector for 2nd side
           inc     dmasd               set side 2 flag
flopsk4    cmpa    #MAXTRK             is it in range?
           bhi     flopsk8             if not - error
           clr     flopskf             clear seek flag
           bsr     flopsd              do side and density setting
           tst     COM1797             check for 'ready'
           lbmi    flopwd              if not, go wait
           cmpa    TRK1797             same track as before?
           lbeq    floprw              if so, skip seek
           sta     DAT1797             set track number in wd
           mul                         delay some
           mul                         delay some more
           lda     #SKCMND             set up seek command
           ora     FD_SRT              set seek rate add on
           sta     COM1797             send to wd command register
           inc     flopskf             set seek flag
           rts                         return
flopsk8    clrb                        set status
           lbra    floper2             report error

           pag

*
* flopdd
*
* Do seek calculations for double density disk.
* Same as above, except 15 sectors per track.
*

flopdd     pshs    b                   save low byte block number
           lsra                        divide block number by 16
           rorb                        by shifting 4 times
           lsra
           rorb
           lsra
           rorb
           lsra
           rorb
           tsta                        in range?
           beq     flopdd2
           puls    b                   clean stack
           bra     flopsk8             report error
flopdd2    tfr     b,a                 put track in a
           puls    b
           andb    #$F                 get remainder
           incb                        adjust sector by 1 (no sec 0)
           clr     dmasd               reset side status
           tst     flopsid             double sided disk?
           beq     flopsk4
           lsra                        adjust track count
           bcc     flopsk4             on to side 2?
           addb    #16                 adjust sector for 2nd side
           inc     dmasd               set side 2 flag
           bra     flopsk4             go finish

           pag

*
* flopsd
*
* Do density and side select.  Also set sector in B.
*

flopsd     stb     SEC1797             set in wd
           clr     cmd_side            assume command side 0
           tst     did_write           still waiting for erase?
           beq     0F
           bsr     wait_write
0          ldb     flophdr             get drive number
           tst     dmasd               set 2nd side?
           beq     flopsd2
           orb     #$10                set 2nd side
           pshs    a                   save register
           lda     flopsid             get side flags
           bita    #$10                side bits valid on disk?
           beq     10F                 no - jump
           lda     #SIDE1              yes - must set bit in command byte
           sta     cmd_side
10         puls    a                   restore register
flopsd2    tst     flopden             double density?
           bne     flopsd4
           orb     #$20                set single density
flopsd4
           lbsr    drvb
           rts                         return

*
* wait_write
*
* Last I/O operation was a write and now the state
* of the drive must change in some way:
*  1) Change drives
*  2) Change tracks
*  3) Change sides
* If any of these take place, we must be assured that
* at least 590 us have elapsed since the I/O completion
* interrupt.
*
wait_write pshs    d,x                 save registers
           clr     did_write           clear flag
           ldx     #167                do a little counting
10         leax    -1,x
           bne     10B
99         puls    d,x,pc              return

pag

*
* dmcsk
*
* Do character device type seek.  If sector
* oriented (xfrc=128, 256, or 1024), then bfblck has
* track and sector.  If track oriented then
* bfblck has track<<1 with low bit being the
* side select bit.
*

dmcsk      cmpd    #1024               check count
           bhi     dmcsk4              >1024 xfr count
           beq     useden
           tst     bfblck,y            get track number
           bne     useden
           clr     flopden             single density for trk zero
useden     clr     dmasd               set side zero
* tst flopsid check if possible side 1
* beq dmcsk2
           cmpd    #128                check for IBM format
           beq     isIBM
           cmpd    #1024               check for IBM S38
           beq     isS38
           lda     #15                 set SD changover
           tst     flopden
           beq     doscmp
isIBM      lda     #26                 set DD changover
           bra     doscmp
isS38      lda     #4
           tst     flopden             check dden
           beq     doscmp
           asla
doscmp     ldb     bfblck+1,y          get sector number
           bmi     expsid
           pshs    a                   push breakover
           subb    0,s+
           bls     dmcsk2              on size zero
           lda     flopsid
           bita    #$20                check separate sides
           beq     ssoflg
expsid     andb    #$7F                strip high bit
           stb     bfblck+1,y
ssoflg     inc     dmasd
dmcsk2     ldd     bfblck,y            get track & sector
dmcsk6     jmp     flopsk4

* track oriented seek

dmcsk4     clr     flopden             clear density
           clr     dmasd               clear side flag
           cmpd    #10200              double density count?
           blo     dmcsk5
           inc     flopden             set double density flag
dmcsk5     lda     bfblck+1,y          get track number
           ldb     #1                  set bogus sector
           lsra                        strip off side bit
           bcc     dmcsk6              if side zero, do seek
           inc     dmasd               set side 2
           bra     dmcsk6

rorb
           pag

*
* floprw
*
* Read write routine for FLOP.  By the time
* control has gotten here, a successful seek
* has been performed.
*

floprw     inc     flopdt+dtbusy       set to next mode of busy (r/w)
floprw2    ldd     bfxfc,y             get transfer count
           cmpd    #16                 is it a swap?
           lbls    dmswp               if so - go do it
           lda     bfflag,y            get buffer flags
           bita    #BFSPC              special i/o?
           bne     flopwtt
           bita    #BFRWF              are we reading?
           beq     flopwt              go do write

*
* floprd
*
* Do dmaf read.  Read 512 bytes bytes into the buffer
* specified by y.
*

floprd     ldb     #$00                set status for CCR
           clr     flopskf             reset seek flag
           lda     #RDCMND             set up read command
           ora     cmd_side            set side bit as needed
           pshs    cc                  retain I mask
           sei                         and mask interrupts
*          sta     COM1797             set command
           bsr     fakedma
           puls    cc                  get I mask back
           rts

*
* flopwt
*
* Do dmaf write.  Write 512 bytes to disk from the
* buffer pointed to by y.
*

flopwt     ldb     #$01                set status for CCR
           lda     #WTCMND             set up command
           tst     flopskf             did we seek?
           beq     flopwt2
           clr     flopskf             reset flag
           lda     #DWTCMD             use head settle write
flopwt2    ora     cmd_side            set side flag as appropriate
           pshs    cc                  retain I mask
           sei
*          sta     COM1797             set command
           sta     did_write           set 'just did a write' flag
           bsr     fakedma             do the transfer
           puls    cc                  get I mask back
           rts

           pag
*
* flopwtt
*
* Do dma write track.
*

flopwtt    ldb     #$01                set status for CCR
           clr     flopskf             reset seek flag
           lda     #WTTCMD             set up command
           bra     flopwt2
*   fakedma
*
*   Do in programmed i/o the equivalent of a dma transfer
*   Mask interrupts during the transfer and enable when finished.
*   Entry cond: b=00  read
*               b=01  write
*               bfxadr,y -> 8 bits of extd address
*               bfadr,y -> 16 bits of addr
*               bfxfc,y -> byte count
*
fakedma
*   A contains the command for the FDC  *NC* NEW CODE TAS 11/6/84
           sta     cmdsav              save command temporarily
           lda     DATRW+2
           pshs    a
           lda     DATRW+1
           pshs    a
           lda     DATRW
           pshs    a
           pshs    dp                  retain the addr map
           lda     #$E8
           tfr     a,dp
           setdp   $E8
           lda     cmdsav         *NC* NEW CODE!!! TAS 11/6/84
           sta     COM1797        *NC* tell FDC about it
           pshs    b                   retain direction
           lda     bfxadr,y            get the page to use
           ldb     bfadr,y         .
           aslb                     .
           rola                      .
           aslb                       .
           rola                        . build DAT entry
           aslb                       .
           rola                      .
           aslb                     .
           rola                    .
           pshs    a                   save extended address for DATBOX
           ldd     bfadr,y             get low order mesg
           anda    #%00001111          make the D page
           tfr     d,x                 12 bit logical offset
           ldy     bfxfc,y             count?
           puls    a                   get back datbox stuff
           sta     DATBOX               stuff the dat for transfer
           inca                          .
           sta     DATBOX+1              .
           inca                          .
           sta     DATBOX+2              .
           puls    b                   get the direction back
           cmpb    #0                  read?
           bne     fwrite              if not, must be a write

fread      lda     ORB29               poll the funny status latch
           bmi     ddrdata             branch if drq bit is set
           beq     fread               loop if busy but no drq
           bra     fakethru            exit if no longer busy

ddrdata    lda     DAT1797             load the FD data register
           sta     0,x+                and store in the buffer
           leay    -1,y                decrement the byte count
           bne     fread               and loop if not finished
           bra     fakethru            terminate if finished

fwrite     lda     0,x+                get the byte from the buffer
fwloop     ldb     ORB29               poll the funny status latch
           bmi     ddwdata             branch if drq bit is set
           beq     fwloop              loop if busy but no drq
           bra     fakethru            exit if no longer busy

ddwdata    sta     DAT1797             and give to FD controller
           leay    -1,y                decrement the byte count
           bne     fwrite              and loop if not finished

fakethru   sty     dmscmp              save count for error check
           puls    dp                  get the map stuff back
           setdp   $00
           puls    d
           std     DATBOX
           puls    a
           sta     DATBOX+2
           rts

* floprs
*
* Restore drive to track zero.  This is done every-
* time a record not found error is detected.  The
* busy status is set to 3 which the interrupt handler
* recognizes as a reseek attempt and will re-issue
* the requested operation.
*

floprs     ldb     flopdt+dtbusy       get status
           cmpb    #4                  swapping?
           beq     floprs2
floprs1    ldb     #3                  set busy status to 3
           stb     flopdt+dtbusy
           lda     #RSCMND             get restore command
           ora     FD_SRT              add on seek rate
           sta     COM1797             send to controller
           rts                         return
floprs2    ldx     dmswpt              get swap pointer
           leax    -1,x                back it up
           stx     dmswpt              save new
           stx     bfadr,y
           bra     floprs1             go restore
           pag

*
* flopint
*
* Interrupt entry for disk drivers.  There are two
* possible entry times.  If 'dtbusy' is 1, then
* the controller has just finished a seek operation.
* If it is 2, we have just finished a read or write.
*

flopint
           lda     #i_1797             clear the via interrupt
           sta     IFR29
           ldy     flopdt+dtqfl        get current transaction
           beq     flopint0            jump if nothing happening
           lda     bfdvn+1,y           get minor device #
           cmpa    #FLOPminor          check legal range
           blo     flopint0
           cmpa    #FLOPminor+3
           bhi     flopint0
           bra     flopin2             go process interrupt
flopint0   ldb     COM1797             reset hardware interrupt
flopin1    rts                         and return
flopin2    lda     flopdt+dtbusy       get busy status
           cmpa    #4                  were we swapping?
           bne     flopin3
           ldb     COM1797             get status
           bitb    #%01101000          various flakeouts
           bne     floper
           ldx     dmscmp
           bne     flopin3
           ldb     #FICMND             force interrupt to WD
           stb     COM1797
           ldx     #32                 wait for command completion
flopin21   leax    -1,x
           bne     flopin21
***        jmp     [$FFFE]
flopi25    ldy     flopdt+dtqfl        get buffer header
           bra     flopi35
flopin3    ldb     COM1797             check if busy
           rorb                        get busy into carry
           bcs     flopin1
           ldy     flopdt+dtqfl        get first transaction
           ldb     COM1797             clear interrupt status
flopi35    cmpa    #1                  were we seeking?
           lbeq    floprw              if so, now go read/write
           cmpa    #3                  were we reseeking?
           bne     flopin4
           clr     flopdt+dtbusy       clear out for retry
           lbra    flopio2             start all over
flopin4    ldb     COM1797             get status
           bitb    #RWOK               any errors?
           beq     flopin5
           bne     floper
flopin5    ldb     flopdt+dtbusy       get status
           cmpb    #4                  are we swapping
           lbeq    dswpdo              go do swap
flopin6    clr     flopdt+dtbusy       clear busy status
           clr     flopdt+dtrtry       clear error count
           ldx     BDtable             restore Block Device Table address
           jmp     BDioend             end of I/O operation
*
*   deselect the drives if a timeout is seen on HLD
*
dselint    lda     #i_unld             clear the flag register
           sta     IFR29
           ldb     #nxdrive            select non-existent drive
           lbsr    drvb                and do the select
           rts


           pag

*
* floper
*
* Handle an error from the controller.  If the
* error count is not max value, bump the count
* and try again.
*

floper     lda     flopdt+dtrtry       get error count
           cmpa    #8                  is it max?
           bhs     floper2
           bitb    #RNFD               is it 'record not found'?
           bne     floper1
           inc     flopdt+dtrtry       bump the error count
           cmpa    #4                  should we reseek?
           lbeq    floprs              if so, call restore
           lda     flopdt+dtbusy       get status
           cmpa    #4                  are we swapping?
           lbne    floprw2             if not - repeat r/w op
           ldx     dmswpt              get swap table ptr
           lda     -1,x                get last segment tried
           lbra    dswpd2              go retry swap
floper1    adda    #4                  bump retry by 4
           sta     flopdt+dtrtry       so do this max of 4 times!
           lbra    floprs              go restore
floper2    stb     bfstat,y            save status
           lda     #FICMND             do force int command
           sta     COM1797             send do wd chip
           pshs    b                   keep the b register????
           ldb     #$27                clear out the drive select
           lbsr    drvb
           puls    b
           lda     bfflag,y            get flags
           ora     #BFERR              set error status
           sta     bfflag,y
           lbra    flopin6

*
* flopwd
*
* Wait for drive ready.
*

flopwd     lda     #WD_MAX             set up counter
           sta     wd_cnt
flopwd00   tfr     y,x                 save parameter
           ldb     IER08               *
           bitb    #i_t2cnt             *CHECKC FOR TIMER TICKS GOING
           bne     flopwd04             ***PATCHES
           ldx     #1766               roughly .5 seconds
flopwd02   leax    -1,x
           pshs    d,x,dp              30 cycles per pass
           puls    d,x,dp
           bne     flopwd02
           bra     flopch
flopwd04   ldb     #5                  set delay (0.5 secomnds)
           ldy     #flopch             set routine address
           lbsr    timout              do a timeout
           rts                         return

*
* flopch
*
* Check if drive is really not ready.
*

flopch     tfr     x,y                 get pointer
           ldb     COM1797             get status
           bpl     10f                 if not busy, go start
           dec     wd_cnt              tried max times?
           bne     flopwd00            no- try again
           bra     floper2             report error

10         clr     flopdt+dtbusy       clear status
           lbra    flopio2

*
* swap to FLOP
*

dmswp      lda     #4                  set status to 4
           sta     flopdt+dtbusy
           ldd     bfadr,y             get swap table pointer
           std     dmswpt              save it
           lda     bfflag,y            check for read or write
           bita    #BFRWF
           beq     dmswp2              ahead if writing
           ldb     #$00                set controller direction
           stb     dmswdr
           ldb     #RDMSCM             setup command
           tst     flopskf             did we seek?
           beq     dmswp1
           orb     #$04                set head settle bit
           clr     flopskf
dmswp1     stb     dmswop
           bra     dswpd1              go do swap
dmswp2     ldb     #$01                set controller direction
           stb     dmswdr
           ldb     #WTMSCM             setup command
           tst     flopskf             did we seek?
           beq     dmswp4
           clr     flopskf             reset seek flag
           ldb     #DWTMSC             set head settle command
dmswp4     stb     dmswop
           stb     did_write           set 'just did a write' flag
           bra     dswpd1              go do swap

*
* dswpdo
*
* Perform a swap operation.
*

dswpdo     ldd     bfblck,y            get block number
           addd    #8                  advance by 8 blocks (4K a crack)
           std     bfblck,y            save it
           bcc     dswpd0              hit hi byte?
           inc     bfblch,y            prop cary
dswpd0     clr     flopdt+dtrtry
           clr     flopdt+dtbusy
           lda     [dmswpt]            get next segment
           cmpa    DSKTRM              end of list?
           lbne    flopio2             if not - repeat
           jmp     flopin6             else - exit
*
*   actual swap code
*
dswpd1     ldx     dmswpt              get swap pointer
           ldb     0,x+                get a segment
           stx     dmswpt              save pointer
           stx     bfadr,y
           cmpb    DSKTRM              end of list?
           lbeq    flopin6             if so - exit
dswpd2     pshs    cc
           sei
           ldx     bfxfc,y             save original count
           stx     dmbc
           ldx     bfadr,y             save original bfadr
           stx     dmadr
           lda     bfxadr,y            save original extended
           sta     dmxadr
           pshs    b
           lsrb
           lsrb
           lsrb
           lsrb
           stb     bfxadr,y
           puls    b
           lslb                        make leftmost nibbles
           lslb
           lslb
           lslb
           stb     bfadr,y             save starting address
           clr     bfadr+1,y           too
           ldx     #4096               set data count
           stx     bfxfc,y
           lda     dmswop
           ora     cmd_side
           ldb     dmswdr
           pshs    y
           lbsr    fakedma
           puls    y
           ldb     dmxadr
           stb     bfxadr,y            save original extended
           ldx     dmadr
           stx     bfadr,y             save original 16 bit
           ldx     dmbc
           stx     bfxfc,y             save original count (16)
           puls    cc
           rts

dmscmp     fdb     0                   byte count for flopint
dmbc       fcb     0,0
dmadr      fcb     0,0
dmxadr     fcb     0
*
* do the actual drive/side select ... delay before if necessary
*

drvb       pshs    a,b                 keep registers
           tfr     b,a                 keep a copy in a
           anda    #fdselABC           keep only the drive number
           cmpa    #nxdrive            non existent drive selected?
           beq     nodrive             if so, just deselect and exit
           orb     #(hltogg+fdmotor+P09229) motor on, ld head, wt. precomp
nodrive    pshs    b
           andb    #(fdside+fdselABC)  look for side or drive change
           cmpb    last_driv           same as last time?
           beq     nowr                skip delay if the same
           tst     did_write           last operation a write?
           beq     nowr                skip delay if wasn't write
           lbsr    wait_write          delay for tunnel erase on drive
nowr       stb     last_driv           store the new stuff
           puls    b                   get the original stuff back
           andb    #($FF-fdside)       remove the unused side bit
           lda     IER08
           bita    #i_t2cnt
           bne     nowr01
           orb     #fdmotor+P09229
nowr01     stb     ORA29               and give to the hardware
           puls    a,b,pc              get registers back

           ttl     Floppy Disk Character Drivers
           pag

*
* The routines in this file make up the character
* device drivers for the floppy disks.  The driver
* code for the drives is shared by the block device
* drivers.
*

*
* fchop
*
* Character disk open routine.  Device number in D.
*

fchop      ldx     #flopopt            point to open table
           subb    #FLOPminor          compute relative drive #
           cmpb    #3                  check for valid drive number
           bhi     fchop4
           tst     b,x                 already open?
           bne     fchop5
           inc     b,x                 set open status
           ldx     #floptrk            point to track table
           abx                         point to drives entry
           clr     4,x                 clear out side info
           clr     8,x                 clear out density
           rts                         return
fchop4     lda     #EBARG              set error
           sta     uerror
fchop5     rts                         return


*
* fchcl
*
* Character disk close routine
*

fchcl      jmp     flopcls             do flop close

           pag

*
* fchrd
*
* Character read routine for floopy disks.
*

fchrd      pshs    d                   save device number
           jsr     fchgb               get device buffer
           puls    d                   reset device number
           jsr     fchcn               configure buffer
           tst     uerror              test for errors
           beq     fchrd4
           bsr     frechbf             release buffer
           rts                         error return
fchrd4     pshs    a                   save task modes byte
           orb     #BFRWF              set read status
           stb     bfflag,y            save in buffer hdr
           bra     fchio               go do io


*
* fchwr
*
* Character write routine for floppy disks.
*

fchwr      pshs    d                   save device number
           bsr     fchgb               get device buffer
           puls    d                   reset device number
           jsr     fchcn               configure buffer
           tst     uerror              check for errors
           beq     fchwr4
           bsr     frechbf
           rts                         error return
fchwr4     pshs    a                   save task mode byte
           bra     fchio               go do io

*
* frechbf - free Floppy Diskette Character buffer
*
frechbf    pshs    d,x,y,u             save registers
           ldy     #fchbuf             point to header
           lda     bfflag,y            get flags
           anda    #!(BFALOC|BFREQ|BFSPC)&$FF clear out busy bits
           sta     bfflag,y            save new flags
           jsr     wakbuf              awake buffer sleepers
           puls    d,x,y,u,pc          return

*
* fchsp
*
* Special routine. Returns side as byte 0, density as 1.
*

fchsp      tfr     x,y                 save pointer
           ldx     #flopsts            point to side table
           subb    #FLOPminor          compute relative drive #
           abx                         point to entry
           cmpy    #0                  doing set or get?
           bne     fchsp4
fchsp2     cmpb    flopdrv             current drive?
           beq     fchsp6
           ldd     usarg0              get arg
           sta     0,x                 set side
           stb     4,x                 set density
           rts                         return
fchsp4     lda     0,x                 get side
           ldb     4,x                 get density
           std     0,y                 save in buffer
           rts                         return
fchsp6     ldd     usarg0              get arg
           sta     0,x                 set side
           stb     4,x                 set density
           sta     flopsid             set current side
           stb     flopden             set current density
           rts                         return

           pag

*
* fchio
*
* Perform the io specified by the buffer header
* pointed at by Y.  ** This routine assumes the
* floppy disks are major device 0 for the block
* type drivers **
*

fchio      pshs    y                   save buffer
           ldx     #blktab             Major Device 0
           jsr     [blkio,x]           call block io routine
           ldy     0,s                 reset buffer
           jsr     fnshio              finish io
           jsr     wakbuf              awakeb buffer sleepers
           puls    y                   reset ptr
           lda     bfflag,y            get flags
           anda    #!(BFALOC|BFREQ|BFSPC)&$FF clear out busy bits
           sta     bfflag,y            save new flags
           puls    a                   get task modes
           ldx     utask               get task entry location
           sta     tsmode,x            save task modes
           ldd     #0                  reset data count to 0
           std     uicnt
fchio6     rts                         return


*
* fchgb
*
* Get the character buffer header.  If it is busy,
* sleep on it.
*

fchgb      ldy     #fchbuf             point to header
           pshs    cc                  save status
           seti
           lda     bfflag,y            get buffer flags
           bita    #BFALOC             is buffer busy?
           beq     fchgb2
           ora     #BFREQ              set request buffer bit
           sta     bfflag,y
           puls    cc                  reset status
           ldb     #BUFPR              set priority
           jsr     sleep               go sleep for buffer
           bra     fchgb               repeat
fchgb2     lda     #BFALOC             set busy status
           sta     bfflag,y
           puls    cc,pc               return

           pag

*
* fchcn
*
* Configure the buffer header pointed at by Y.
* This routine sets up the character device info
* from the user block and puts it in the buffer
* header such that the device drivers can use
* the information for the data transfer.
*

fchcn      std     bfdvn,y             save device number
           ldd     uicnt               get xfr count
           std     bfxfc,y             save in header
           cmpd    #128                check for valid number
           beq     fchcn4
           cmpd    #256                is it a sector operation?
           beq     fchcn4
           cmpd    #512                is it 512 byte op?
           beq     fchcn4
           cmpd    #5100               is it a write track?
           beq     fchcn2
           cmpd    #10200              is it dd write track?
           bne     fchcn8              if not - error
fchcn2     lda     bfflag,y            get flags
           ora     #BFSPC              set special bit for drivers
           sta     bfflag,y            save new flags
fchcn4     ldd     uipos2              get file position
           std     bfblck,y            save as block number
           lda     uipos+1             store upper part
           sta     bfblch,y
           ldd     uistrt              get start address of xfr
           std     bfadr,y             save in header
           jsr     mapupg              find user page
           std     bfxadr,y            save in header
           ldx     utask               point to task entry
           lda     tsmode,x            get mode bits
           pshs    a                   save
           ora     #TLOCK              set lock bit (keep in mem)
           sta     tsmode,x            save new mode
           ldb     bfflag,y            get flags
           puls    a,pc                return
fchcn8     lda     #EBARG              set error
           sta     uerror
           rts                         return
