Retrocomputing

Device driver for G68 floppy disk drive

The G68 floppy disk drive controller card was sold for the GIMIX systems

         nam   G68
         ttl   os9 device driver

         use  defsfile

         mod  DSKEND,DSKNAM,DRIVR+OBJCT,REENT+1,DSKENT,DSKSTA
         fcb  DIR.+SHARE.+PREAD.+PWRIT.+UPDAT.+EXEC.+PEXEC.
DSKNAM   fcs  "G68"
         fcb  5          Edition

         pag
*********************************************************************
*
* Static Storage
*
*
         org  Drvbeg
         rmb  Drvmem*DriveCnt

CURTBL   rmb  2          Ptr to current drive tbl
CURDRV   rmb  1          Drive select bit pattern
V.SEL    rmb  2          Drive select reg addr./DMA Status register
V.DMACTL rmb  2
V.DMAADR rmb  2          DMA address register
V.CMDR   rmb  2
V.TRKR   rmb  2
V.SECR   rmb  2
V.DATR   rmb  2
V.SIDE   rmb  1          Current side; 0:=side 0
V.DENS   rmb  1
u00BA    rmb  1
V.FDSTA  rmb  1          FD status
V.EXTDMA rmb  1          Extended DMA address (lower nibble)
V.TMP    rmb  1          Temporary save byte
V.EFLG   rmb  1          Set "e" for head settle time
V.BUF    rmb  2          Local buffer addr
V.DOSK   rmb  1          Force seek flag
V.FREZ   rmb  1          Freeze dd. info (for one read0)

DSKSTA   equ  .

******************************************************************
*
* Branch Table
*
DSKENT   lbra INIDSK     Initialize i/o
         lbra READSK
         lbra WRTDSK
         lbra Getsta
         lbra PUTSTA
         lbra Termnt

DMA.INT  equ  %10000000  Interrupt enable
DMA.SD1  equ  %01000000  Side select - side one
DMA.WRI  equ  %00100000  DMA direction - write
DMA.ENA  equ  %00010000  DMA enabled

DMA.FLT  equ  %00001000  DMA Fault flag

F.REST   equ  $0B        Restore command
F.SEEK   equ  $1B        Seek command
F.STPI   equ  $4B        Step in one track command
F.READ   equ  $88        Read sector command
F.WRIT   equ  $A8        Write sector command
F.TYP1   equ  $D0        Force type 1 status
F.WRTR   equ  $F4        Write track command

FDMASK   fcb  $00        no flip bits
         fcb  $40
         fcb  $01

PUTSTA   ldx  PD.RGS,Y   Point to parameters
         ldb  R$B,X      Get stat call
         cmpb #SS.Reset  Restore call?
         lbeq RESTOR     ..yes; do it.
         cmpb #SS.WTrk   Write track call?
         lbeq WRTTRK     ..yes; do it.
         cmpb #SS.FRZ    Freeze dd. info?
         beq  SETFRZ     Yes; ....flag it.
         cmpb #SS.SPT    Set sect/trk?
         beq  SETSPT     Yes; ....set it.
GETSTA   comb            ...NO; Error
         ldb  #E$UnkSvc  Error code
         rts

SETFRZ   ldb  #$FF
         stb  V.FREZ,u   Set flag
         clrb
         rts


SETSPT   lbsr SELECT     Find drive table
         ldd  R$X,x      Get input sect/trk
         ldx  CURTBL,u   Point to drive table
         stb  DD.TKS,x
         clrb
         rts
         pag
****************************************************************
*
* Initialize The I/O Port
*
*  Input: (U)= Pointer To Global Storage
*
*  On Exit: (A) Modified
*           (X) Modified
*           (Y) Unchanged
*           (U) Unchanged
*
INIDSK   ldx  V.PORT,U   Point to i/o port
         stx  V.SEL,u
         leax 1,x        DMA Control register
         stx  V.DMACTL,u
         leax 1,x        DMA starting address
         stx  V.DMAADR,u
         leax 2,x        FD1797 Command/status register
         lda  #F.TYP1
         sta  0,x        Inz controller chip
         stx  V.CMDR,u
         leax 1,x        FD1797 Track register
         stx  V.TRKR,u
         leax 1,X        FD1797 sector register
         stx  V.SECR,U
         leax 1,x        FD1797 Data register
         stx  V.DATR,u
         lda  #$FF
         ldb  #DriveCnt
         stb  V.NDRV,U   Inz number of drives
         leax DRVBEG,U   Point to first drive table
INILUP   sta  DD.TOT,x   Inz to non-zero
         sta  V.TRAK,X   Inz to high track count
         leax DRVMEM,X   Point to next drive table
         decb            DONE
         bne  INILUP     ...no; inz more.
         ldd  #256       "d" passes memory req size
         pshs U          Save "u" we need it later
         OS9  F$SRqMem   Request 1 pag of mem
         tfr  U,X
         puls U
         bcs  RETRN1
         stx  V.BUF,u
         ldd  V.SEL,u
         leax FDMASK,pcr
         leay <IRQSVC,pcr
         os9  F$IRQ
         bcs  RETRN1
         clrb
RETRN1   rts

IRQSVC   ldb  [V.CMDR,u]
         coma
         lda  V.WAKE,u
         beq  IRQEND     Nothing waiting
         tst  V.TMP,u
         beq  ISVC01
         clr  D.DMAReq
ISVC01   stb  V.FDSTA,u
         ldb  #S$Wake
         clr  V.WAKE,u
         os9  F$Send
         clrb
IRQEND   rts

         pag
*********************************************************
*
* Restore Drive To Track Zero
*
*  Input: (Y)= Pointer To Path Descriptor
*         (U)= Pointer To Global Storage
*
*  If Error: (B)= Error Code & Carry Is Set
*
* Note:  We Are Stepping In Several Tracks Before
*        Issuing The Restore.  As Suggested In The
*        Application Notes.
*
RESTOR   lbsr SELECT     Select drive
         bcs  RETRN1
         ldx  CURTBL,U
         clr  V.TRAK,X   Old track = 0
         lda  #5         Repeat five times
RESTR2   pshs a
         ldb  PD.STP,y
         andb #$03
         eorb #F.STPI
         clr  V.TMP,u
         bsr  WCR0
         puls a
         deca
         bne  RESTR2
         ldb  PD.STP,y
         andb #$03
         eorb #F.REST
         bra  WCR0
***************************************************************
*
* Write Sector Command
*
* Input:
*   B = Msb Of Logical Sector Number
*   X = Lsb'S Of Logical Sector Number
*   Y = Ptr To Path Descriptor
*   U = Ptr To Global Storage
*
*
* Error:
*   Carry Set
*   B = Error Code
*
WRTDSK   lda  #$91       Error retry code
L0108    pshs x,b,a
         bsr  L013B
         bcc  L011E
         cmpb #$F6
         beq  L0151
         cmpb #$F2
         beq  L0151
         tst  ,s
         beq  L0151
         puls x,b,a
         bra  L0130
L011E    tst  ,s
         lbeq WRERR
         puls x,b,a
         tst  PD.VFY,y
         bne  RETRN1
         lbsr WRTVFY
         bcc  RETRN1
L0130    lsra
         bcc  L0108
         pshs x,b,a
         bsr  RESTOR
         puls x,b,a
         bra  L0108

L013B    lbsr SEEK
         lbcs RETRN1
         ldx  PD.BUF,y
         lda  #$30
         sta  V.TMP,u
         ldb  #F.WRIT
         bsr  WCR0
         lbra STCK

L0151    stb  $01,s
         comb
         puls pc,x,b,a


WCR0     lda  V.TMP,u
         beq  L016E
         bsr  DMAADDR    Set DMA buffer address
L0160    lda  D.DMAReq   Wait for other DMA to finish
         beq  L016C
         ldx  #1
         os9  F$Sleep
         bra  L0160

*********************************************************
*
* Set the DMA extended address from logical address
*
* Input: (X)=logical address
* Data: V.EXTDMA

DMAADDR
         pshs B
         tfr  X,D
         anda #$F0
         lsra            Shift block number to lower nibble
         lsra
         lsra
         ldy  D.SysDAT   Get system DAT
         ldd  A,Y        get block number
         clra
         lsrb            set the DMA extended bits
         rora
         lsrb
         rora
         lsrb
         rora
         lsrb
         rora
         stb  V.EXTDMA,u
         pshs A          make copy of block number
         pshs X
         lda  0,S
         anda #$0F
         ora  2,S        load the high nibble of block
         sta  0,S
         puls X
         stx  [V.DMAADR,u] Set buffer address
         puls A
         puls B
         rts
         pag

L016C    inc  D.DMAReq
L016E    lda  CURDRV,u
         bmi  L017E
         tst  PD.STP,y
         bpl  L017E
         tstb
         bmi  L017E
         ora  #$C0
L017E    tst  >u00BA,u
         bne  L0186
         ora  #$10       Write enable
L0186    sta  [>V.SEL,u]
         lda  >V.TMP,u
         tst  V.SIDE,u   Is it side 1?
         beq  L0196      .. no
         ora  #DMA.SD1   select side 1
L0196    ora  #DMA.INT   Enable interrupts

* LEVEL2 Or in the extended bank address here
         ora  V.EXTDMA,u

         sta  [V.DMACTL,u]
         tst  V.TMP,u
         beq  L01B2
         orb  V.EFLG,u
         clr  V.EFLG,u
         tst  V.SIDE,u
         beq  L01B2
         orb  #$02
L01B2    lda  V.BUSY,u
         sta  V.WAKE,u
         stb  [>V.CMDR,u]
L01BA    ldx  #$0032
         os9  F$Sleep
         tst  [>V.TRKR,u]
         lda  V.WAKE,u
         bne  L01BA
         lda  >V.FDSTA,u
         tst  PD.STP,y
         bpl  L01E2
         tstb
         bmi  L01E2
         lda  CURDRV,u
         sta  [V.SEL,u]
         bsr  DELAY
         lda  [V.CMDR,u]
L01E2    rts


DELAY    ldb  #$17
DELAY1   decb
         bne  DELAY1
         rts

         pag
*************************************************************
*
* Read Sector Command
*
* Input: B = Msb Of Logical Sector Number
*        X = Lsb'S Of Logical Sector Number
*        Y = Ptr To Path Descriptor
*        U = Ptr To Global Storage
*
* Output: 256 Bytes Of Data Returned In Buffer
*
* Error: Cc=Set, B=Error Code
*
READSK   lda  #$91       Error retry code
         cmpx #0         Is this sector zero?
         bne  RDDSK3     Branch if not
         lbra READ0      Do read of sector zero


RDDSK1   bcc  RDDSK3     Retry without restore
         pshs D,X
         lbsr RESTOR     Drive to tr00
         puls D,X
RDDSK3   pshs x,b,a
         bsr  READSC
         bcc  L0221
         cmpb #E$NotRdy
         lbeq L0151
         puls x,b,a
         lsra
         bne  RDDSK1
READSC   bsr  SEEK
         bcs  L01E2
         ldx  PD.BUF,y
         lda  #$10
         sta  V.TMP,u
         ldb  #F.READ
         lbsr WCR0
         lbra READCK
L0221    leas $04,s
         clrb
         rts
***************************************************************
*
* Seek A Track
*
* Input:
*   B = Msb Of Logical Sector Number
*   X = Lsb'S Of Logical Sector Number
*
* Output:
*   X = Physical Sector Number
*   A,B = Undefined
*
* Error:
*   Carry Set
*   B = Error Code
*
SEEK     bsr  SELECT     Select drive
         bcs  RETRN2     Drive out of range?
         bsr  PHYSIC     Convert to physical sect + track
         bcs  RETRN2     Sector out of range?
         lbra SETTRK     Set up for track change

         pag
***************************************************************
*
* Select Drive
*
*  Input: (U)= Pointer To Global Storage
*
* Output: Curtbl,U=Current Drive Tbl
*         Curdrv,U=Drive Number
*
SELECT   lda  PD.DRV,Y   Get drive number
         cmpa V.NDRV,U   Drive num ok?
         bhs  ERUNIT
         clr  >V.DOSK,u
         pshs X,D        Save regs
         leax DRVBEG,U   Table beginning
         ldb  #DRVMEM
         mul             OFFSET For this drive
         leax D,X
         cmpx CURTBL,u
         beq  L0268
         com  V.DOSK,u
         stx  CURTBL,u
         clr  [V.SEL,u]
         lda  [V.TRKR,u]
         sta  [V.DATR,u]
         clra
         sta  V.TMP,u
         ldb  #$13
         lbsr L0196
L0268    puls a
         leax <L0290,pcr
         ldb  PD.TYP,y
         andb #$01
         beq  L0276
         ldb  #$C0
L0276    orb  a,x
         stb  [>V.SEL,u]
         stb  >CURDRV,u
         clr  >V.SIDE,u
         lda  #$20
         sta  >V.DENS,u
         puls pc,x,b


ERUNIT   comb
         ldb  #E$UNIT    Error: illegal unit (drive)
RETRN2   rts

L0290    fcb  1,2,4,8

         pag
**************************************************************
*
* Convert Logical Sector Number
* To Physical Track And Sector
*
*  Input:  B = Msb Of Logical Sector Number
*          X = Lsb'S Of Logical Sector Number
*  Output: A = Physical Track Number
*          Sector Reg = Physical Sector Number
*  Error:  Carry Set & B = Error Code
*
PHYSIC   tstb            CHECK Sector bounds
         bne  PHYERR     msb must be zero
         tfr  X,D        Logical sector (os-9)
         cmpd #0         Logical sector zero?
         beq  PHYSC7     ..yes; skip conversion.
         ldx  CURTBL,U
         cmpd DD.TOT+1,X Too high sector number?
         bhs  PHYERR     ..yes; sorry
         subd <PD.T0S,y On side 1 track zero?
         bcc  PHYSC1     .. branch if higher
         addd <PD.T0S,y
         bra  PHYSC7

PHYSC1   stb  >V.TMP,u
         clrb
         pshs B          Will be track number
         ldb  DD.FMT,X   Disk format from disk identification sector
         lsrb            SHIFT Side bit to carry
         ldb  V.TMP,U    Restore (b)
         bcc  PHYSC4     Single sided disk

* Calculate track for double sided disk
PHYSC2   com  >V.SIDE,u Flip side
         bne  PHYSC3
         inc  0,S        Increment track number
PHYSC3   subb DD.TKS,X
         sbca #0
         bcc  PHYSC2     Repeat until less than 1 trk
         bra  PHYSC5

* Calculate track for single sided disk
PHYSC4   inc  0,S        Increment track number
         subb DD.TKS,X
         sbca #0
         bcc  PHYSC4     Repeat until less than 1 trk

PHYSC5   lda  DD.FMT,X
         bita #$02       Check density
         beq  PHYSC6     Branch if single density
         clr  >V.DENS,u
PHYSC6   puls a
         addb DD.TKS,x
PHYSC7   stb  [>V.SECR,u]
         clrb
         rts

PHYERR   comb
         ldb  #E$SECT    Error: bad sector number
         rts
         pag

Settrk   pshs a
         ldb  >V.DENS,u
         orb  CURDRV,U   Mask into drive select
         stb  CURDRV,U   Save it
         stb  [V.SEL,u]
         ldx  CURTBL,U   Point to drive table
         ldb  V.TRAK,X   Get old track
         pshs b
         ldb  DD.Fmt,x
         lsrb
         eorb Pd.Dns,y
         bitb #%00000010 Drive and media same?
         beq  Setrk3
         asla
         asl  0,s
Setrk3   puls b
         stb  [V.TRKR,U] Put old track in trk reg
         ldb  [V.CMDR,u]
         bpl  SETRK6
         clr  [V.SEL,u]
         ldb  CURDRV,u
         stb  [V.SEL,u]
         lbsr DELAY
         ldx  #4000      Set delay
SETRK4   ldb  [V.CMDR,u]
         bpl  SETRK6
         pshs x
         ldx  #1         Give up timeslice
         os9  F$Sleep
         puls x
         leax -1,x
         bne  SETRK4
         leas 1,s
         bra  ERNRDY
SETRK6   tst  V.DOSK,u   Force seek?
         bne  SETRK8
         ldb  0,s        Get true track number
         cmpb V.TRAK,X   Same track?
         beq  SETRK9
SETRK8   sta  [V.DATR,u] Put new trk in data reg
         ldb  PD.STP,y
         andb #$03
         eorb #F.SEEK
         clr  V.TMP,u
         lbsr WCR0       Issue command
         lda  #4
         sta  V.EFLG,U
SETRK9   puls a
         ldx  CURTBL,u
         sta  V.Trak,x
         sta  [V.Trkr,u] Put true track number everywhere
         clrb
         rts
         pag
***********************************************************
*
* Check Status For Error Conditions
*
*  Input: (B)= Status Of Fd1797
*
*  If Error: (B)= Error Code & Carry Is Set
*
*  If No Error: Carry Is Clear
*
STCK     bita #%01000000 Write protected?
         bne  WPERR
READCK   bita #%00000100 Lost data?
         bne  RDWRER
         bita #%00001000 Check sum ok?
         bne  ERRCRC
         bita #%00010000
         bne  ERSEEK
         bita #%10000000 Drive ready?
         bne  ERNRDY     ..no; error
         clrb
         rts

ERRCRC   comb
         ldb  #E$CRC     Error: bad check sum
         rts

ERSEEK   comb
         ldb  #E$SEEK    Error: seek error
         rts

RDWRER   ldb  V.TMP,u
         bitb #%00100000 Write fault?
         bne  RDERR
WRERR    comb
         ldb  #E$Write
         rts
RDERR    comb
         ldb  #E$Read
         rts
ERNRDY   comb
         ldb  #E$NotRdy
WRERR9   rts

WPERR    comb
         ldb  #E$WP
         rts
         pag
****************************************************************
*
* Read Logical Sector Zero
*
*
*
READ0    lbsr RDDSK3     Read sector
         bcs  WRERR9
         ldx  PD.BUF,Y
         pshs X,Y
         tst  V.Frez,u   Skip copy of dd. info?
         bne  Read03     Yes; ....make quick exit
         ldy  CURTBL,U
         ldb  #DD.SIZ-1
READ01   lda  B,X
         sta  B,Y
         decb
         bpl  READ01
         lda  DD.FMT,Y
         ldy  2,S        Restore (y)
         ldb  Pd.Dns,y   Get drive capabilities
         bita #%00000010 Media dden?
         beq  L03EB
         bitb #%00000001 Drive dden?
         beq  TYPERR
L03EB    bita #%00000100 Media dbl track dens?
         beq  Read03
         bitb #%00000010 Drive dbl track dens?
         beq  Typerr     No; .....incompatible media
Read03   bita #%00000001 Dbl sided?
         beq  READ05     ...no; we can handle it.
         lda  PD.SID,Y
         suba #2
         bcs  TYPERR
READ05   clr  V.FREZ,u
         clrb
         puls X,Y,PC

TYPERR   comb
         ldb  #E$BTYP
         puls X,Y,PC

WRTTRK   lbsr SELECT
         bcs  WRERR9     Error; report it
         lda  R$U+1,X    Track number
         ldb  R$Y+1,X    Side/density info
         ldx  Curtbl,u   Point to drive table
         stb  DD.Fmt,x   Update media format byte
         bitb #%00000001 Side zero?
         beq  WRTRK2     ..yes; skip side change
         com  V.SIDE,U
WRTRK2   bitb #%00000010 Double density?
         beq  WRTRK5     ..yes
         clr  >V.DENS,u
WRTRK5   lbsr SETTRK
         ldx  PD.RGS,Y
         ldx  R$X,X      Get buffer addr
         ldb  #F.WRTR
         lda  #$30
         sta  V.TMP,u
         lbsr WCR0
         ldb  [V.SEL,u]
         bitb #DMA.FLT
         beq  WRTRK9
         lda  #%10000000 Set drive ready status
WRTRK9   lbra STCK       Check status
         pag
*********************************************
*
* Write Verify Routine
*
*
*    Reads back the sector just written
*    Returns carry set if bad sector
*    Compares 'read' data to 'write' data
*    Returns carry set if no compare
*  Note: Only the first 128 bytes are compared
*        assuming that any other error will cause
*        a bad Crc.

WRTVFY   pshs D,X
         ldx  PD.BUF,Y   Save present buffer addr
         pshs X          On stack
         ldx  V.BUF,U    Point to local buffer
         stx  PD.BUF,Y
         ldx  4,S        Restore (x)
         lbsr READSK
         puls X
         stx  PD.BUF,Y   Restore buffer pointer
         bcs  WRTVF6     Error; ...try again
         pshs u,y
         ldy  V.BUF,u    Point "y" to local buffer
         tfr  x,u
         clra
         ldb  #$80
         leay d,y
         leau d,u        Bump both pointers
WRTCHK   ldx  a,y        Get two bytes
         cmpx a,u        Check with 'read data'
         bne  WRTVF2
         suba #2
         bne  WRTCHK     No; ....keep checking
         bra  WRTVF4
WRTVF2   orcc #%00000001 Set carry
WRTVF4   puls u,y
WRTVF6   puls pc,x,d
         pag
**************************************
*
* Terminate use of the disk
*
*
*    Return Local memory to the system
*
*

Termnt   clr  [V.DMACTL,u]
         ldx  #0
         os9  F$IRQ
         ldu  V.BUF,u
         ldd  #256
         OS9  F$SRtMem   Return local buffer to free mem
         rts
         emod

DSKEND   equ  *

         end