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