Mercurial > hg > Members > kono > nitros9-code
changeset 1631:ec6fb5543b22
Robert Gault's modifications for correcting timing errors
author | boisy |
---|---|
date | Mon, 12 Jul 2004 01:38:08 +0000 |
parents | 7af4d12008f4 |
children | 93d5b9ff0f4a |
files | level1/modules/rb1773.asm |
diffstat | 1 files changed, 1325 insertions(+), 1301 deletions(-) [+] |
line wrap: on
line diff
--- a/level1/modules/rb1773.asm Tue Jul 06 15:08:24 2004 +0000 +++ b/level1/modules/rb1773.asm Mon Jul 12 01:38:08 2004 +0000 @@ -1,1301 +1,1325 @@ -******************************************************************** -* rb1773 - Western Digital 1773 Disk Controller Driver -* -* $Id$ -* -* This driver has been tested with the following controllers: -* - Tandy FD-502 "shortie" disk controller -* - Disto Super Controller I -* - Disto Super Controller II -* -* This driver can also be assembled to support the no-halt feature of -* the Disto Super Controller II. -* -* -* A lot of references to **.CYL or <u00B6 using 16 bit registers can be -* changed to 8 bit registers with a +1 offset, since track #'s >255 are -* ignored -* -* NOTE: 512 bytes is reserved as a physical sector buffer. Any reads/ -* writes are done from this buffer to the controller. Copies of the 256 -* byte chunk needed are done by a block memory move -* -* -********** DISTO SUPER CONTROLLER II NOTES ********** -* -* SCII 0=standard controller 1=Disto Super Controller II -* SCIIALT 0=Normal I/O register 1=Alternative registers; See below -* -* Disto Super Controller II Registers: -* -* $FF74 RW.Dat --- R/W Buffer data #1 -* $FF75 mirror of $FF74 -* $FF76 RW.Ctrl --- Write D0 = 0 FDC Write Op #2 -* = 1 FDC Read Op #2 -* D1 = 0 Normal Mode -* = 1 Buffered I/O Mode -* D2 = 0 Normal NMI -* = 1 Masked NMI -* D3 = 0 No FIRQ (Masked) -* = 1 Enabled FIRQ -* Read D7 = FDC INT Status (Inverted) -* $FF77 mirror of $FF76 -* #1: any write to $FF76-$FF77 clears Buffer counter -* #2: in buffered mode only -* -* Alternate port is at $FF58-$FF5B in case of hardware conflicts. -* -* Edt/Rev YYYY/MM/DD Modified by -* Comment -* ------------------------------------------------------------------ -* 11 1993/05/12 ??? -* Special opts for TC9 to slow controller reads and writes TFM's -* between sector buffers & in drive table init/copies. -* Changed software timing loop (drive spin-up) to F$Sleep for 32 ticks -* Shrunk (slowed slightly) error returns -* Added blobstop code -* -* 11r1 2003/09/03 Boisy G. Pitre -* Added code to sense if HW is present or not and return error if not. -* -* 1r0 2004/05/20 Boisy G. Pitre -* Restarted edition due to name change; backported to Level 1 -* -* 2004/06/01 Robert Gault -* Added code to obtain an SCII driver, at least for the Sleep mode. It -* would be quite difficult and probably not worth the effort to permit -* selection of both Sleep and IRQ SCII drivers. However, both normal -* and Alt SCII I/O registers are supported. -* -* Cleaned up some errors in the last version of rb1773. - - nam rb1773 - ttl Western Digital 1773 Disk Controller Driver - -* These lines needed if assembling with on a Color computer. -*SCII set 1 * 0=not present 1=present -*SCIIALT set 1 * 0=normal address 1=alternate -SCIIHACK set 0 * 0=stock model 1=512 byte buffer -*H6309 set 1 -*LEVEL set 2 -* These lines needed if not using latest os9def files. -*TkPerSec set 60 -*DPort set $FF40 - -* This should be changed for NitrOS9 project to "use defsfile" - IFP1 - use defsfile - ENDC - -tylg set Drivr+Objct -atrv set ReEnt+rev -rev set $00 -edition set 1 - -* Configuration Settings -N.Drives equ 4 number of drives to support -TC9 equ 0 Set to 1 for TC9 special slowdowns -PRECOMP equ 0 Set to 1 to turn on write precompensation - -* Disto Super Controller defs - IFEQ SCIIALT -RW.Dat equ $FF74 -RW.Ctrl equ $FF76 - ELSE -RW.Dat equ $FF58 -RW.Ctrl equ $FF5A - ENDC - - -* WD-17X3 Definitions -CtrlReg equ $00 Control register for Tandy controllers; not part of WD -WD_Cmd equ $08 -WD_Stat equ WD_Cmd -WD_Trak equ $09 -WD_Sect equ $0A -WD_Data equ $0B - -* WD-17X3 Commands -S$Read equ $80 Read sector -S$Format equ $A0 Format track -S$FrcInt equ $D0 Force interrupt - -* Control Register Definitions -C_HALT equ %10000000 Halt line to CPU is active when set -C_SIDSEL equ %01000000 Side select (0 = front side, 1 = back side) -C_DBLDNS equ %00100000 Density (0 = single, 1 = double) -C_WPRCMP equ %00010000 Write precompensation (0 = off, 1 = on) -C_MOTOR equ %00001000 Drive motor (0 = off, 1 = on) -C_DRV2 equ %00000100 Drive 2 selected when set -C_DRV1 equ %00000010 Drive 1 selected when set -C_DRV0 equ %00000001 Drive 0 selected when set - - mod eom,name,tylg,atrv,start,size - -u0000 rmb DRVBEG+(DRVMEM*N.Drives) -lastdrv rmb 2 Last drive table accessed (ptr) -ctlimg rmb 1 Bit mask for control reg (drive #, side,etc) -u00AA rmb 1 drive change flag -sectbuf rmb 2 Ptr to 512 byte sector buffer -currside rmb 1 head flag; 0=front 1 = back -u00AE rmb 1 LSB of LSN - IFGT Level-1 -FBlock rmb 2 block number for format -FTask rmb 1 task number for format - ENDC -VIRQPak rmb 2 Vi.Cnt word for VIRQ -u00B3 rmb 2 Vi.Rst word for VIRQ -u00B5 rmb 1 Vi.Stat byte for VIRQ (drive motor timeout) -loglsn rmb 2 OS9's logical sector # -* Removed next line and added two new ones. RG -* PCDOS does not ask driver for any info. -* physlsn rmb 2 PCDOS (512 byte sector) # -flag512 rmb 1 PCDOS (512 byte sector) 0=no, 1=yes -flagform rmb 1 SCII format flag -size equ . - - fcb DIR.+SHARE.+PEXEC.+PWRIT.+PREAD.+EXEC.+UPDAT. - -name fcs /rb1773/ - fcb edition - -VIRQCnt fdb TkPerSec*4 Initial count for VIRQ (4 seconds) - -IRQPkt fcb $00 Normal bits (flip byte) - fcb $01 Bit 1 is interrupt request flag (Mask byte) - fcb 10 Priority byte - -* Init -* -* Entry: -* Y = address of device descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -* New code added 09/03/2003 by Boisy G. Pitre -* Write a pattern to $FF4B and read it back to verify that the hardware -* does exist. -Init equ * -* Two new lines for SCII. RG - IFNE SCII - clr RW.Ctrl clear SCII control register - clr flagform,u clear SCII format flag - ENDC - ldx V.PORT,u get Base port address - lda WD_Data,x get byte at FDC Data register - coma complement it to modify it - sta WD_Data,x write it - clrb -Init2 decb delay a bit... - bmi Init2 - suba WD_Data,x read it back - lbne NoHW if not zero, we didn't read what we wrote -** - IFEQ Level-1 - clr >D.DskTmr flag drive motor as not running - ELSE - clr <D.MotOn flag drive motor as not running - ENDC - leax WD_Stat,x point to Status/Command register - lda #S$FrcInt "Force Interrupt" command - sta ,x send to FDC - lbsr FDCDelay time delay for ~ 108 cycles - lda ,x eat status register - ldd #$FF*256+N.Drives 'invalid' value & # of drives - leax DRVBEG,u point to start of drive tables -l1 sta ,x DD.TOT MSB to bogus value - sta <V.TRAK,x init current track # to bogus value - leax <DRVMEM,x point to next drive table - decb done all drives yet? - bne l1 no, init them all - leax >NMISvc,pc point to NMI service routine - IFGT Level-1 - stx <D.NMI install as system NMI - ELSE - stx >D.XNMI+1 NMI jump vector operand - lda #$7E JMP code - sta >D.XNMI NMI jump vector opcode - ENDC - pshs y save device dsc. ptr - leay >u00B5,u point to Vi.Stat in VIRQ packet - tfr y,d make it the status register ptr for IRQ - leay >IRQSvc,pc point to IRQ service routine - leax >IRQPkt,pc point to IRQ packet - os9 F$IRQ install IRQ - puls y Get back device dsc. ptr - bcs Return If we can't install IRQ, exit - ldd #512 Request 512 byte sector buffer - pshs u Preserve device mem ptr - os9 F$SRqMem Request sector buffer - tfr u,x Move ptr to sector buffer to x - puls u Restore device mem ptr - bcs Return If error, exit with it - stx >sectbuf,u Save ptr to sector buffer - -* GetStat -* -* Entry: -* A = function code -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -GetStat clrb no GetStt calls - return, no error, ignore -Return rts - -* Term -* -* Entry: -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -Term leay >VIRQPak,u Point to VIRQ packet - IFNE H6309 - tfr 0,x "remove" - ELSE - ldx #$0000 - ENDC - os9 F$VIRQ Remove VIRQ - IFNE H6309 - tfr 0,x "remove" - ELSE - ldx #$0000 - ENDC - leay >IRQSvc,pc point to IRQ service routine - os9 F$IRQ Remove IRQ - pshs u Save device mem ptr - ldu >sectbuf,u Get pointer to sector buffer - ldd #512 Return sector buffer memory - os9 F$SRtMem - puls u Restore device mem ptr - clr >DPort+CtrlReg shut off drive motors - IFEQ Level-1 - clr >D.DskTmr Clear out drive motor timeout flag - ELSE - clr <D.MotOn Clear out drive motor timeout flag - ENDC -ex rts return - -* Check if 512 byte sector conversion needed -* Entry: B:X=LSN -* U=Static mem ptr -* Y=Path dsc. ptr -* Exit: X=New LSN (same as original for 256 byte sectors, 1/2 of original -* for 512 byte sectors -* regD changed -Chk512 equ * - clr flag512,u set to 256 byte sector - stx >loglsn,u save OS9 LSN - lda <PD.TYP,y get device type from path dsc. - anda #%00000100 mask out all but 512 byte sector flag - bne Log2Phys 512 byte sectors, go process - rts RG - -* 512 byte sector processing goes here -* regB should be saved and not just cleared at end because there is -* a subsequent tst for the msb of lsn. The test is pointless if B -* is changed. -Log2Phys pshs b save MSB of LSN; new RG -* Minor inefficiencies here that I have changed, RG - tfr x,d - IFNE H6309 - lsrd - ELSE - lsra - rorb - ENDC - tfr d,x move new LSN back to regX -* New line for stock SCII controller with 256 max no-halt. - inc flag512,u set to 512 byte sector - puls b,pc regB will be tested later for >0 - -start lbra Init - bra Read - nop - lbra Write - bra GetStat - nop - lbra SetStat - bra Term - nop - -* Read -* -* Entry: -* B = MSB of LSN -* X = LSB of LSN -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -Read bsr Chk512 go check for 512 byte sector/adjust if needed - lda #%10010001 error flags (see Disto SCII source) - pshs x preserve sector # - lbsr ReadWithRetry go read the sector - puls x restore sector # - bcs ex if error, exit - pshs y,x save path dsc ptr & LSN - leax ,x LSN0?, ie. tstx - bne L012D no, go calculate normally - puls y,x yes, restore path dsc ptr & LSN - lda <PD.TYP,y get type from path dsc. - bita #TYP.NSF standard OS-9 format? - beq L00F0 yes, skip ahead - lbsr MakeDTEntry else make a drive table entry - pshs y,x save path dsc ptr - bra L012D - -* LSN0, standard OS-9 format - copy part of LSN0 into drive table -L00F0 ldx >sectbuf,u Get ptr to sector buffer - pshs y,x Preserve path dsc. ptr & sector buffer ptr - ldy >lastdrv,u Get last drive table accessed ptr - IFNE H6309 - ldw #DD.SIZ # bytes to copy from new LSN0 to drive table - tfm x+,y+ Copy them - ELSE - ldb #DD.SIZ -L00F0Lp lda ,x+ - sta ,y+ - decb - bne L00F0Lp - ENDC - ldy >lastdrv,u Get drive table ptr back - lda <DD.FMT,y Get format for disk in drive - ldy 2,s restore path descriptor pointer - ldb <PD.DNS,y Get path's density settings - bita #FMT.DNS Disk in drive double density? - beq L0115 No, all drives can read single, skip ahead - bitb #DNS.MFM Can our path dsc. handle double density? - beq erbtyp No, illegal -L0115 bita #FMT.TDNS Is new disk 96/135 tpi? - beq L011D No, all drives handle 48 tpi, so skip ahead - bitb #DNS.DTD Can path dsc. handle 96/135 tpi? - beq erbtyp No, illegal -L011D bita #FMT.SIDE Is new disk double sided? - beq L0128 No, all drives handle single sided, we're done - lda <PD.SID,y Get # sides path dsc. can handle - suba #2 sides higher or equal to 2? - blo erbtyp Yes, exit with illegal type error -L0128 clrb No error -* LSN's other than 0 come straight here -L012D ldy 2,s Get path dsc. ptr back?? - ldx PD.BUF,y Get path dsc. buffer ptr -* lda <PD.TYP,y Get path dsc. disk type, RG - ldy >sectbuf,u Get ptr to sector buffer - IFNE H6309 - ldw #256 OS9 sector size (even if physical was 512) - ENDC -* anda #%00000100 Mask out all but 512 byte sector flag, RG -* Next replaces the two lines removed, RG - tst flag512,u Is it a 512 byte sector? - beq L014B If normal sector, just copy it - ldd >loglsn,u Get OS9's LSN (twice of the 'real' 512 sector) - andb #$01 Mask out all but odd/even sector indicator - beq L014B Even, use 1st half of 512 byte sector - IFNE H6309 - addr w,y Odd, bump sector buffer ptr to 2nd half - ELSE - leay 256,y - ENDC -L014B equ * - IFNE H6309 - tfm y+,x+ Copy from physical sector buffer to PD buffer - puls pc,y,x restore path dsc & sector buffer ptrs & return - ELSE - pshs d - clrb -L014BLp lda ,y+ - sta ,x+ - decb - bne L014BLp - puls pc,y,x,d restore path dsc & sector buffer ptrs & return - ENDC - -erbtyp comb - ldb #E$BTyp Error - wrong type error - puls pc,y,x - -********************** -* Read error - retry handler -Retry - bcc ReadWithRetry Normal retry, try reading again - pshs x,d Preserve regs - lbsr sktrk0 Seek to track 0 (attempt to recalibrate) - puls x,d Restore regs & try reading again - - -* Read With Retry: Do read with retries -* -* ENTER reg B,X=working lsn on disk -* Y=path descriptor -* U=driver data -* A=retry sequence mix of read & seek track 0 -* EXIT X,Y,U preserved; D,CC changed -* B=error if any -* CC=error flag -ReadWithRetry - pshs x,d Preserve regs - bsr ReadSector Go read sector - puls x,d Restore regs (A=retry flags) - lbcc L01D7 No error, return - lsra Shift retry flags - bne Retry Still more retries allowed, go do them -* otherwise, final try before we give up -ReadSector - lbsr L02AC Do double-step/precomp etc. if needed, seek - lbcs L01D7 Error somewhere, exit with it -L0176 ldx >sectbuf,u Get physical sector buffer ptr - ldb #S$Read Read sector command - IFNE SCII -* If SCII not hacked for 512 byte no-halt, must use halt for 512b sectors RG - IFEQ SCIIHACK - clra SCII normal mode, normal NMI - tst flag512,u SCII must use halt mode for 512 byte sectors - bne L0176B - ENDC - lda #7 SCII read, buffered mode, masked NMI - bsr L01A1B send commands and wait - lbcs L03AF get the errors - IFNE H6309 - pshs y - ldw #128 set counter - ldy #RW.DAT source of data - IFNE SCIIHACK - tst flag512,u - beq sc2rlp - ldw #256 bump up counter to 512 byte sector - ENDC -* Don't use tfm if no halt important else need orcc #$50 for tfm -* If an interrupt occurs during a tfm transfer, the SCII counter -* will update but the tfm will repeat a byte and lose track. -* If orcc #$50 used, then key presses may be lost even with no-halt -* mode. -sc2rlp ldd ,y read two bytes from SCII - std ,x++ transfer two bytes to system buffer - decw update counter - bne sc2rlp - ELSE - ldy #128 - IFNE SCIIHACK - tst flag512,u - beq sc2rlp - ldy #256 - ENDC -sc2rlp ldd >RW.DAT - std ,x++ - leay -1,y - bne sc2rlp - ENDC - clrb no errors - puls y,pc - ENDC - -L0176B bsr L01A1 Send to controller & time delay to let it settle -*** Next few lines are commented out for blobstop patches -*L0180 bita >DPort+WD_Stat check status register -* bne L0197 eat it & start reading sector -* leay -1,y bump timeout timer down -* bne L0180 keep trying until it reaches 0 or sector read -* lda >ctlimg,u get current drive settings -* ora #C_MOTOR turn drive motor on -* sta >DPort+CtrlReg send to controller -* puls y,cc restore regs -* lbra L03E0 exit with Read Error -*** Blobstop fixes - stb >DPort+CtrlReg send B to control register - nop allow HALT to take effect - nop - bra L0197 and a bit more time -* Read loop - exited with NMI -* Entry: X=ptr to sector buffer -* B=Control register settings -L0197 lda >DPort+WD_Data get byte from controller - sta ,x+ store into sector buffer -* stb >DPort+CtrlReg drive info - nop -- blobstop fix - bra L0197 Keep reading until sector done - -L01A1 orcc #IntMasks Shut off IRQ & FIRQ -* No-halt mode must enter here, skipping IRQ shutoff. -L01A1B stb >DPort+WD_Cmd Send command - IFNE SCII - sta >RW.Ctrl tell SCII what to do - ENDC -L01A1C ldb #C_DBLDNS+C_MOTOR Double density & motor on - orb >ctlimg,u Merge with current drive settings - stb >DPort+CtrlReg Send to control register - IFNE SCII - tst flagform,u Format uses halt mode - bne s512 - IFEQ SCIIHACK - tst flag512,u SCII uses halt with 512 byte sectors - beq s256 - ELSE - bra s256 - ENDC - ENDC -s512 ldb #C_HALT+C_DBLDNS+C_MOTOR Enable halt, double density & motor on - orb >ctlimg,u Merge that with current drive settings - lbra FDCDelay Time delay to wait for command to settle - IFNE SCII -s256 ldb #4 normal mode, NMI masked - lda #255 time out slices - pshs a,x -SC2tmr1 ldx #1 - lbsr Delay sleep or timer - dec ,s count - beq tmout - tst >RW.Ctrl check status - bmi SC2tmr1 loop on not ready - stb RW.Ctrl clear SCII but don't generate NMI - clrb - puls a,x,pc -tmout stb RW.Ctrl clear SCII buffer counter - lda #$D0 force interrupt - sta DPort+WD_Cmd - comb set carry - puls a,x,pc - ENDC - -* Delay for some number of ticks (1 tick = 1/60 second). -* For a hard delay, we need to delay for 14833 cycles at .89MHz or -* 29666 cycles at 1.78MHz -* Entry: X = number of ticks to delay -Delay - pshs d [5+] [4+] - IFGT Level-1 - ldd <D.Proc [6] [5] process pointer - cmpd <D.SysPrc [is it the system? - beq hardloop [3] [3] - os9 F$Sleep if not system then sleep - puls d,pc [5+] [4+] - ENDC -hardloop tfr x,d we want X in A,B -l1@ equ * - IFEQ Level-1 - ldx #1482/2 [3] [3] - ELSE - IFNE H6309 - ldx #1854 [3] [3] - ELSE - ldx #1482 [3] [3] - ENDC - ENDC -l2@ nop [2] [1] - nop [2] [1] - nop [2] [1] - leax -1,x [4+] [4+] - bne l2@ [3] [3] - subd #$0001 [4] [3] - bne l1@ [3] [3] - puls d,pc [5+] [4+] - -* Write -* Entry: -* B = MSB of LSN -* X = LSB of LSN -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -Write lbsr Chk512 go adjust LSN for 512 byte sector if needed -* Next line was lda #%1001001 which was an error RG - lda #%10010001 retry flags for I/O errors (see Disto SCII source) -L01C4 pshs x,d preserve LSN, retries - bsr L01E8 go write the sector - puls x,d restore LSN, retries - bcs L01D8 error writing, go to write retry handler - tst <PD.VFY,y no error, do we want physical verify? - bne L01D6 no, exit without error - lbsr verify go re-read & verify 64 out of 256 bytes - bcs L01D8 error on verify, go to write retry handler -L01D6 clrb no error & return -L01D7 rts - -* Write error retry handler -L01D8 lsra Shift retry flags - lbeq L03AF Too many retries, exit with error - bcc L01C4 Normal retry, attemp to re-write sector - pshs x,d Preserve flags & sector # - lbsr sktrk0 Seek to track 0 (attempt to recalibrate) - puls x,d Restore flags & sector # - bra L01C4 Try re-writing now - -* 512 byte sector write here -L01E8 lbsr L02AC Go do double-step/write precomp if needed - bcs L01D7 Error, exit with it - pshs y,d Preserve path dsc. ptr & LSN -* Since I have modified chk512 the next two lines are replaced. RG -* lda <PD.TYP,y Get device type -* anda #%00000100 512 byte sector? - tst flag512,u go if 256 byte sectors - beq L020D Not 512 then skip ahead - lbsr L0176 Go read the sector in - ldd >loglsn,u Get OS9 LSN - andb #$01 Even or odd? - beq L020D Even, skip ahead - ldx >sectbuf,u Get physical sector buffer ptr - leax >$0100,x Point to 2nd half - bra L0211 Copy caller's buffer to 2nd half of sector - -L020D ldx >sectbuf,u Get physical sector buffer ptr - -L0211 ldy PD.BUF,y Get path dsc. buffer ptr - IFNE H6309 - ldw #256 Copy write buffer to sector buffer - tfm y+,x+ - ELSE - clrb -L0211Lp lda ,y+ - sta ,x+ - decb - bne L0211Lp - ENDC - puls y,d Get path dsc. ptr & LSN back - ldx >sectbuf,u Get physical sector buffer ptr again -* See read routine for explanation of SCII code. RG - IFNE SCII - IFEQ SCIIHACK - clra SCII write, normal mode & NMI - tst flag512,u - bne wr512 - ENDC - lda #4 SCII normal mode, masked NMI - sta RW.Ctrl tell SCII - pshs y - ldy #RW.Dat Send data to SCII RAM buffer - IFNE H6309 - ldw #128 - tst flag512,u - beq wrbuf - ldw #256 -wrbuf ldd ,x++ - std ,y - decw - bne wrbuf - ELSE - ldy #128 - tst flag512,u - beq wrbuf - ldy #256 -wrbuf ldd ,x++ - std >RW.DAT - leay -1,y - bne wrbuf - ENDC - puls y - ldb #$A0 Write sector command - lda #6 SCII masked NMI, buffered mode, write - lbra L01A1B send command to controller - ENDC -wr512 ldb #S$Format - -* Format track comes here with B=$F0 (write track) -* as does write sector with B=$A0 -*WrTrk pshs y,cc Preserve path dsc. ptr & CC -WrTrk lbsr L01A1 Send command to controller (including delay) -*** Commented out for blobstop fixes -*L0229 bita >DPort+WD_Stat Controller done yet? -* bne L0240 Yes, go write sector out -* leay -$01,y No, bump wait counter -* bne L0229 Still more tries, continue -* lda >ctlimg,u Get current drive control register settings -* ora #C_MOTOR Drive motor on (but drive select off) -* sta >DPort+CtrlReg Send to controller -* puls y,cc Restore regs -* lbra L03AF Check for errors from status register - -*** added blobstop - IFGT Level-1 - lda FBlock+1,u get the block number for format - beq L0230 if not format, don't do anything - sta >$FFA1 otherwise map the block in - ENDC -L0230 stb >DPort+CtrlReg send data to control register -* These lines added to match read routine. Should be better timing. RG - nop - nop - bra L0240 wait a bit for HALT to enable - -* Write sector routine (Entry: B= drive/side select) (NMI will break out) -* Part of timing change mentioned above. RG -*L0240 nop --- wait a bit more -L0240 lda ,x+ Get byte from write buffer - sta >DPort+WD_Data Save to FDC's data register -* EAT 2 CYCLES: TC9 ONLY (TRY 1 CYCLE AND SEE HOW IT WORKS) - IFEQ TC9-1 - nop - nop - ELSE -* See above. RG - nop - ENDC -* stb >DPort+CtrlReg Set up to read next byte - bra L0240 Go read it - -* NMI routine -NMISvc leas R$Size,s Eat register stack - IFGT Level-1 - ldx <D.SysDAT get pointer to system DAT image - lda 3,x get block number 1 - sta >$FFA1 map it back into memory - ENDC - andcc #^IntMasks turn IRQ's on again - ldb >DPort+WD_Stat Get status register - IFNE SCII - clr RW.Ctrl Clear SCII command register - ENDC - bitb #%00000100 Did we lose data in the transfer? - lbeq L03B2 Otherwise, check for drive errors - comb -- blobstop error code - ldb #E$DevBsy -- device busy - rts -- and exit - -verify pshs x,d -* Removed unneeded code. Data never sent to PD.BUF anyway so there is -* no need to redirect the PD.BUF pointer. RG -* ldx PD.BUF,y Get write buffer ptr -* pshs x Preserve it -* ldx >sectbuf,u Get sector buffer ptr -* stx PD.BUF,y Save as write buffer ptr -* ldx 4,s - lbsr ReadSector Go read sector we just wrote -* puls x Get original write buffer ptr -* stx PD.BUF,y Restore path dsc. version - bcs L02A3 If error reading, exit with it - ldx PD.BUF,y Get system buffer ptr - pshs u,y Preserve device mem, path dsc. ptrs -* See change in chk512 routine. RG -* ldb <PD.TYP,y Get type from path dsc. - ldy >sectbuf,u Get sector buffer ptr -* andb #%00000100 512 byte sector? - tst flag512,u 512 byte sector? - beq L028D No, skip ahead - ldd >loglsn,u Get OS9's sector # - andb #$01 Odd/even sector? - beq L028D Even; compare first half - leay >$0100,y Odd, compare second half -L028D tfr x,u Move PD.BUF ptr to U (since cmpx is faster) - clra check all 256 bytes -L028F ldx ,u++ Get 2 bytes from original write buffer - cmpx ,y++ Same as corresponding bytes in re-read sector? - bne vfybad No, error & return - inca - bpl L028F No, continue - bra L02A1 carry is clear by virtue of last cmpx -vfybad comb set carry -L02A1 puls u,y -L02A3 puls pc,x,d - -L02A5 pshs a Save Caller's track # - ldb <V.TRAK,x Get track # drive is currently on - bra L02E9 Go save it to controller & continue - -L02AC lbsr L0376 Go set up controller for drive, spin motor up - bsr L032B Get track/sector # (A=Trk, B=Sector) - pshs a Save track # - lda >currside,u Get side 1/2 flag - beq L02C4 Side 1, skip ahead - lda >ctlimg,u Get control register settings - ora #C_SIDSEL Set side 2 (drive 3) select - sta >ctlimg,u Save it back -L02C4 lda <PD.TYP,y Get drive type settings - bita #%00000010 ??? (Base 0/1 for sector #?) - bne L02CC Skip ahead - incb Bump sector # up by 1 -L02CC stb >DPort+WD_Sect Save into Sector register - ldx >lastdrv,u Get last drive table accessed - ldb <V.TRAK,x Get current track # on device - lda <DD.FMT,x Get drive format specs - lsra Shift track & bit densities to match PD - eora <PD.DNS,y Check for differences with path densities - anda #%00000010 Keep only 48 vs. 96/135 tpi differences - pshs a Save differences - lda 1,s Get track # back - tst ,s+ Are tpi's different? - beq L02E9 No, continue normally - lsla Yes, multiply track # by 2 ('double-step') - lslb Multiply current track # by 2 ('double-step') -L02E9 stb >DPort+WD_Trak Save current track # onto controller - -* From here to the line before L0307 is for write precomp, but is not used. -* Unless write precomp is needed, all of this is useless -* I think most (if not all) drives do NOT need precomp - IFEQ PRECOMP-1 - ldb #21 Pre-comp track # - pshs b Save it - ldb <PD.DNS,y Get current density settings - andb #%00000010 Just want to check track density - beq L02F9 48 tpi, skip ahead - lsl ,s Multiply pre-comp value by 2 ('double-step') -L02F9 cmpa ,s+ Is track # high enough to warrant precomp? - bls L0307 No, continue normally - ldb >ctlimg,u - orb #C.WRPCMP Turn on Write precomp - stb >ctlimg,u - ENDC - -L0307 tst >u00AA,u ??? Get flag (same drive flag?) - bne L0314 no, skip ahead - ldb ,s get track # - cmpb <V.TRAK,x same as current track on this drive? - beq L0321 yes, skip ahead -L0314 sta >DPort+WD_Data save track # to data register - ldb <PD.STP,y get stepping rate - andb #%00000011 just keep usable settings (6-30 ms) - eorb #%00011011 set proper bits for controller - lbsr L03E4 send command to controller & time delay -L0321 puls a get track # back - sta <V.TRAK,x save as current track # - sta >DPort+WD_Trak save to controller - clrb no error & return - rts - -* Entry: B:X LSN -* Exit: A=Track # -* B=Sector # -* <currside=00 = Head 1 , $FF = Head 2 -L032B tstb Sector # > 65535? - bne L033F Yes, illegal for floppy - tfr x,d Move sector # to D - leax ,x LSN 0? ie. "tstx" - beq L0371 Yes, exit this routine - ldx >lastdrv,u Get previous drive table ptr - cmpd DD.TOT+1,x Within range of drive spec? - blo L0343 Yes, go calculate track/sector #'s -L033F comb Exit with Bad sector # error - ldb #E$Sect - rts - -* Calculate track/sector #'s? -* These two sections could be combined into one with a final -* test of DD.FMT. Then currside can be set and regA can be lsra -* as needed. RG -L0343 stb >u00AE,u Save LSB of LSN - clr ,-s Clear track # on stack - ldb <DD.FMT,x Get drive format - lsrb Shift out # sides into carry - ldb >u00AE,u Get LSB of LSN again - bcc L0367 Single sided drive, skip ahead - bra L035D Double sided drive, skip ahead -* Double sided drive handling here -L0355 com >currside,u Odd/even sector track flag - bne L035D Odd, so don't bump track # up - inc ,s Bump up track # - -* Changed this to more effient code. RG -*L035D subb DD.TKS,x Subtract # sectors/track -* sbca #$00 -L035D subd DD.SPT,x - bcc L0355 Still more sectors left, continue - bra L036D Wrapped, skip ahead -* Single sided drive handling here -L0365 inc ,s Bump track # up - -* See above. RG -*L0367 subb DD.TKS,x Subtract # sectors/track -* sbca #$00 -L0367 subd DD.SPT,x - bcc L0365 Still more, go bump the track up -* Next possible because upper limit is 256 sectors/track. RG -L036D addb DD.TKS,x Bump sector # back up from negative value - puls a Get the track # -L0371 rts A=track #, B=Sector #, <currside=Odd - -* Drive control register bit mask table -* May want an option here for double sided SDDD disks ex. RG -* fcb $1 drive0 -* fcb $2 drive1 -* fcb $41 drive2 -* fcb $42 drive3 -* fcb $4 drive4 -* fcb $44 drive5 - -L0372 fcb $01 Drive 0 - fcb $02 Drive 1 - fcb $04 Drive 2 - fcb $40 Drive 3 / Side select - -* Changes regD; X,Y,U preserved -L0376 clr >u00AA,u clear drive change flag -chkdrv lda <PD.DRV,y Get drive # requested - cmpa #4 Drive 0-3? - blo L0385 Yes, continue normally -NoHW comb Illegal drive # error - ldb #E$Unit - rts - -* Entry: A=drive #, X=LSN (Physical, not OS9 logical if PCDOS disk) -L0385 pshs x,d Save sector #, drive # & B??? - leax >L0372,pc Point to drive bit mask table - ldb a,x Get bit mask for drive # we want - stb >ctlimg,u Save mask - leax DRVBEG,u Point to beginning of drive tables - ldb #DRVMEM Get size of each drive table - mul Calculate offset to drive table we want - leax d,x Point to it - cmpx >lastdrv,u Same as Last drive table accessed? - beq L03A6 Yes, skip ahead - stx >lastdrv,u Save new drive table ptr - com >u00AA,u Set drive change flag -L03A6 clr >currside,u Set side (head) flag to side 1 - lbsr L04B3 Go set up VIRQ to wait for drive motor - puls pc,x,d Restore sector #,drive #,B & return - -L03AF ldb >DPort+WD_Stat Get status register from FDC -L03B2 bitb #%11111000 any of the error bits set? - beq L03CA No, exit without error - aslb Drive not ready? - bcs L03CC Yes, use that error code - aslb Write protect error? - bcs L03D0 Yes, use that error code - aslb Write fault error? - bcs L03D4 Yes, use that error code - aslb Sector not found? - bcs L03D8 Yes, use Seek error code - aslb CRC error? - bcs L03DC Yes, use that error code -L03CA clrb No error & return - rts - -L03CC ldb #E$NotRdy not ready - fcb $8C skip 2 bytes - -L03D0 ldb #E$WP write protect - fcb $8C skip 2 bytes - -L03D4 ldb #E$Write write error - fcb $8C - -L03D8 ldb #E$Seek seek error - fcb $8C - -L03DC ldb #E$CRC CRC error -* fcb $8C - -*L03E0 ldb #E$Read Read error - orcc #Carry set carry - rts - -L03E4 bsr L0404 Send command to controller & waste some time -L03E6 ldb >DPort+WD_Stat Check FDC status register - bitb #$01 Is controller still busy? - beq L0403 No, exit - ldd >VIRQCnt,pc Get initial count value for drive motor speed - std >VIRQPak,u Save it -* Again, I'm trying to match Kevin Darling code. It may not be needed. RG - pshs x - ldx #1 Sleep remainder of slice - lbsr Delay - puls x - bra L03E6 Wait for controller to finish previous command - -* Send command to FDC -L03F7 lda #C_MOTOR -* lda #%00001000 Mask in Drive motor on bit - ora >ctlimg,u Merge in drive/side selects - sta >DPort+CtrlReg Turn the drive motor on & select drive - stb >DPort+WD_Cmd Save command & return -L0403 rts - -L0404 bsr L03F7 Go send command to controller - -* This loop has been changed from nested LBSRs to timing loop. -* People with crystal upgrades should modify the loop counter -* to get a 58+ us delay time. MINIMUM 58us. -FDCDelay - pshs a 14 cycles, plus 3*loop counter - IFEQ Level-1 - lda #18 (only do about a 100 cycle delay for now) - ELSE - lda #29 (only do about a 100 cycle delay for now) - ENDC -L0409 deca for total ~63 us delay (123 cycles max.) - bne L0409 - puls a,pc restore register and exit - -* SetStat -* -* Entry: -* A = function code -* Y = address of path descriptor -* U = address of device memory area -* -* Exit: -* CC = carry set on error -* B = error code -* -SetStat ldx PD.RGS,y Get caller's register stack ptr - ldb R$B,x Get function code - cmpb #SS.WTrk Write track? - beq SSWTrk Yes, go do it - cmpb #SS.Reset Restore head to track 0? - lbeq sktrk0 Yes, go do it --- beq - comb set carry for error - ldb #E$UnkSvc return illegal service request error - rts - -SSWTrk pshs u,y preserve register stack & descriptor - -* Level 2 Code - IFGT Level-1 - -*--- new code - ldb #1 1 block to allocate - os9 F$AllRAM allocate some RAM - lbcs L0489 error out if at all - leax >FBlock,u point to 'my' DAT image - std ,x save a copy of the block - os9 F$ResTsk reserve a task number for the copy - bcs FError error out - stb 2,x save temporary task number in FTask,u - lslb 2 bytes per entry - ldu <D.TskIPt get task image table pointer - stx b,u save pointer to the task's DAT image - lsrb get the right number again - IFNE H6309 - tfr 0,u destination is address 0 - ELSE - ldu #$0000 - ENDC -*--- end new code - - ldx 2,s get pointer to descriptor -* stu >FBlock,x - ldx <D.Proc Get current process ptr - lda P$Task,x Get task # for current process -* ldb <D.SysTsk Get system task # - ldy ,s - ldx PD.RGS,y Get register stack ptr - ldx R$X,x Get ptr to caller's track buffer - ldy #$1A00 Size of track buffer - os9 F$Move Copy from caller to temporary task - bcs L0479 Error copying, exit - puls u,y - pshs u,y - - ENDC -* End of Level 2 Code - - lbsr L0376 Go check drive #/wait for it to spin up - ldx PD.RGS,y Get caller's register stack ptr - ldb R$Y+1,x Get caller's side/density - bitb #$01 Check side - beq L0465 Side 1, skip ahead -* I think this next line is not needed. RG - com >currside,u * Why? This is normally used with -* calculate track. RG - ldb >ctlimg,u Get current control register settings -* orb #%01000000 Mask in side 2 - orb #C_SIDSEL Mask in side 2 - stb >ctlimg,u Save updated control register -L0465 lda R$U+1,x Get caller's track # - ldx >lastdrv,u Get current drive table ptr - lbsr L02A5 - bcs L0489 - ldb #$F0 Write track command -*--- - IFEQ Level-1 - ldx PD.RGS,y - ldx R$X,x - ELSE - ldx #$2000 start writing from block 1 - ENDC - - IFNE SCII - lda #1 normal unbuffered write -* Next line prevents WrTrk from switching to SCII buffered mode. RG - sta flagform,u - ENDC - lbsr WrTrk Go write the track - IFNE SCII - clr flagform,u permit no-halt mode RG - ENDC - - IFGT Level-1 -L0479 ldu 2,s - pshs b,cc Preserve error - ldb >FTask,u point to task - os9 F$RelTsk release the task - fcb $8C skip 2 bytes - -* format comes here when block allocation passes, but task allocation -* gives error. So er de-allocate the block. -FError - pshs b,cc save error code, cc - ldx >FBlock,u point to block - ldb #1 1 block to return - os9 F$DelRAM de-allocate image RAM blocks - clr FBlock+1,u ensure that the block # in FBlock is zero. - puls b,cc Restore error - ENDC - -L0489 puls pc,u,y Restore regs & return - -* seek the head to track 0 -sktrk0 lbsr chkdrv - ldx >lastdrv,u - clr <$15,x - lda #1 was 5 but that causes head banging -L0497 ldb <PD.STP,y - andb #%00000011 Just keep usable settings (6-30 ms) - eorb #%01001011 Set proper bits for controller - pshs a - lbsr L03E4 - puls a - deca - bne L0497 - ldb <PD.STP,y - andb #%00000011 Just keep usable settings (6-30 ms) - eorb #%00001011 Set proper bits for controller - lbra L03E4 - -L04B3 pshs y,x,d Preserve regs - ldd >VIRQCnt,pc Get VIRQ initial count value - std >VIRQPak,u Save it - lda >ctlimg,u ?Get drive? - ora #C_MOTOR Turn drive motor on for that drive -* ora #%00001000 Turn drive motor on for that drive - sta >DPort+CtrlReg Send drive motor on command to FDC - IFEQ Level-1 - lda >D.DskTmr Get VIRQ flag - ELSE - lda <D.MotOn Get VIRQ flag - ENDC - bmi L04DE Not installed yet, try installing it - bne L04E0 Drive already up to speed, exit without error - -* Drive motor speed timing loop (could be F$Sleep call now) (was over .5 sec) -* 32 was not sufficient for one of my drives. RG - ldx #50 wait for 32 ticks; increased it RG - lbsr Delay - -L04DE bsr InsVIRQ Install VIRQ to wait for drive motors -L04E0 clrb No error & return - puls pc,y,x,d - -InsVIRQ lda #$01 Flag drive motor is up to speed - IFEQ Level-1 - sta >D.DskTmr - ELSE - sta <D.MotOn - ENDC - ldx #$0001 Install VIRQ entry - leay >VIRQPak,u Point to packet - clr Vi.Stat,y Reset Status byte - ldd >VIRQCnt,pc Get initial VIRQ count value - os9 F$VIRQ Install VIRQ - bcc VIRQOut No error, exit - lda #$80 Flag that VIRQ wasn't installed - IFEQ Level-1 - sta >D.DskTmr - ELSE - sta <D.MotOn - ENDC -VIRQOut clra - rts - -* IRQ service routine for VIRQ (drive motor time) -* Entry: U=Ptr to VIRQ memory area -IRQSvc pshs a - lda <D.DMAReq - beq L0509 - bsr InsVIRQ - bra IRQOut -L0509 sta >DPort+CtrlReg -* I changed this to a clear. Don't see the point of an AND. RG -* IFNE H6309 -* aim #$FE,>u00B5,u -* ELSE -* lda u00B5,u -* anda #$FE -* sta u00B5,u -* ENDC -* fdb u00B5 --- so changes in data size won't affect anything - clr u00B5,u - IFEQ Level-1 - clr >D.DskTmr - ELSE - clr <D.MotOn - ENDC -IRQOut puls pc,a - -* Non-OS9 formatted floppies need a drive table entry constructed -* by hand since there is no RBF LSN0. -* -* Entry: X=LSN -* Y=Path dsc. ptr -* U=Device mem ptr -MakeDTEntry - pshs x Preserve Logical sector # - ldx >lastdrv,u Get last drive table accessed ptr - clra - pshs x,a Save ptr & NUL byte - IFNE H6309 - ldw #20 Clear 20 bytes - tfm s,x+ - ELSE - ldb #20 -L051ALp clr ,x+ - decb - bne L051ALp - ENDC - puls x,a Eat NUL & get back drive table ptr - ldb <PD.CYL+1,y Get # cylinders on drive (ignores high byte) - lda <PD.SID,y Get # sides - mul Calculate # tracks on drive (1 per head) - IFNE H6309 - decd Adjust to ignore track 0 - ELSE - subd #$0001 - ENDC - lda <PD.SCT+1,y Get # sectors/track - sta DD.TKS,x Save in drive table - sta <DD.SPT+1,x Save in other copy in drive table - mul Calculate # sectors on drive (minus track 0) - pshs x Preserve drive table ptr - tfr d,x Move # sectors on drive to X - lda <PD.T0S+1,y Get # sectors on track 0 - leax a,x Add that many sectors to total - lda <PD.TYP,y Get device type settings - anda #%00000100 Mask out all but 512 byte sector flag - beq L0550 Not 512 byte sector, skip ahead - IFNE H6309 - addr x,x Multiply by 2 (convert to 256 byte OS9 sectors) - ELSE - tfr x,d - leax d,x - ENDC -L0550 tfr x,d Move # sectors to D - puls x Get back drive table ptr - std DD.TOT+1,x Save # sectors allowed on drive - lda #UPDAT.+EXEC. Owner's read/write/exec attributes - sta DD.ATT,x Set attributes for disk - lda <PD.DNS,y Get density settings - lsla Shift for DD.FMT - pshs a Preserve it a sec - lda <PD.SID,y Get # sides - deca Adjust to base 0 - ora ,s+ Merge with density settings - sta <DD.FMT,x Save in device table - clrb No error? - puls pc,x Restore original LSN & return - - emod -eom equ * - end +******************************************************************** +* rb1773 - Western Digital 1773 Disk Controller Driver +* +* $Id$ +* +* This driver has been tested with the following controllers: +* - Tandy FD-502 "shortie" disk controller +* - Disto Super Controller I +* - Disto Super Controller II +* +* This driver can also be assembled to support the no-halt feature of +* the Disto Super Controller II. +* +* +* A lot of references to **.CYL or <u00B6 using 16 bit registers can be +* changed to 8 bit registers with a +1 offset, since track #'s >255 are +* ignored +* +* NOTE: 512 bytes is reserved as a physical sector buffer. Any reads/ +* writes are done from this buffer to the controller. Copies of the 256 +* byte chunk needed are done by a block memory move +* +* +********** DISTO SUPER CONTROLLER II NOTES ********** +* +* SCII 0=standard controller 1=Disto Super Controller II +* SCIIALT 0=Normal I/O register 1=Alternative registers; See below +* +* Disto Super Controller II Registers: +* +* $FF74 RW.Dat --- R/W Buffer data #1 +* $FF75 mirror of $FF74 +* $FF76 RW.Ctrl --- Write D0 = 0 FDC Write Op #2 +* = 1 FDC Read Op #2 +* D1 = 0 Normal Mode +* = 1 Buffered I/O Mode +* D2 = 0 Normal NMI +* = 1 Masked NMI +* D3 = 0 No FIRQ (Masked) +* = 1 Enabled FIRQ +* Read D7 = FDC INT Status (Inverted) +* $FF77 mirror of $FF76 +* #1: any write to $FF76-$FF77 clears Buffer counter +* #2: in buffered mode only +* +* Alternate port is at $FF58-$FF5B in case of hardware conflicts. +* +* Edt/Rev YYYY/MM/DD Modified by +* Comment +* ------------------------------------------------------------------ +* 11 1993/05/12 ??? +* Special opts for TC9 to slow controller reads and writes TFM's +* between sector buffers & in drive table init/copies. +* Changed software timing loop (drive spin-up) to F$Sleep for 32 ticks +* Shrunk (slowed slightly) error returns +* Added blobstop code +* +* 11r1 2003/09/03 Boisy G. Pitre +* Added code to sense if HW is present or not and return error if not. +* +* 1r0 2004/05/20 Boisy G. Pitre +* Restarted edition due to name change; backported to Level 1 +* +* 2004/06/01 Robert Gault +* Added code to obtain an SCII driver, at least for the Sleep mode. It +* would be quite difficult and probably not worth the effort to permit +* selection of both Sleep and IRQ SCII drivers. However, both normal +* and Alt SCII I/O registers are supported. +* +* Cleaned up some errors in the last version of rb1773. +* +* 2004/07/11 Robert Gault +* Corrected the error handling code for read & write to separate SCII errors +* from OS-9 errors. Changed drive test from compare #4 to compare #N.Drives to +* permit up to 6 drives using alternate table. + + nam rb1773 + ttl Western Digital 1773 Disk Controller Driver + +* These lines needed if assembling with on a Color computer. +*SCII set 1 * 0=not present 1=present +*SCIIALT set 1 * 0=normal address 1=alternate +SCIIHACK set 0 * 0=stock model 1=512 byte buffer +*H6309 set 1 +*LEVEL set 2 +* These lines needed if not using latest os9def files. +*TkPerSec set 60 +*DPort set $FF40 + +* This should be changed for NitrOS9 project to "use defsfile" + IFP1 + use defsfile + ENDC + +tylg set Drivr+Objct +atrv set ReEnt+rev +rev set $00 +edition set 1 + +* Configuration Settings +N.Drives equ 4 number of drives to support +TC9 equ 0 Set to 1 for TC9 special slowdowns +PRECOMP equ 0 Set to 1 to turn on write precompensation + +* Disto Super Controller defs + IFEQ SCIIALT +RW.Dat equ $FF74 +RW.Ctrl equ $FF76 + ELSE +RW.Dat equ $FF58 +RW.Ctrl equ $FF5A + ENDC + + +* WD-17X3 Definitions +CtrlReg equ $00 Control register for Tandy controllers; not part of WD +WD_Cmd equ $08 +WD_Stat equ WD_Cmd +WD_Trak equ $09 +WD_Sect equ $0A +WD_Data equ $0B + +* WD-17X3 Commands +S$Read equ $80 Read sector +S$Format equ $A0 Format track +S$FrcInt equ $D0 Force interrupt + +* Control Register Definitions +C_HALT equ %10000000 Halt line to CPU is active when set +C_SIDSEL equ %01000000 Side select (0 = front side, 1 = back side) +C_DBLDNS equ %00100000 Density (0 = single, 1 = double) +C_WPRCMP equ %00010000 Write precompensation (0 = off, 1 = on) +C_MOTOR equ %00001000 Drive motor (0 = off, 1 = on) +C_DRV2 equ %00000100 Drive 2 selected when set +C_DRV1 equ %00000010 Drive 1 selected when set +C_DRV0 equ %00000001 Drive 0 selected when set + + mod eom,name,tylg,atrv,start,size + +u0000 rmb DRVBEG+(DRVMEM*N.Drives) +lastdrv rmb 2 Last drive table accessed (ptr) +ctlimg rmb 1 Bit mask for control reg (drive #, side,etc) +u00AA rmb 1 drive change flag +sectbuf rmb 2 Ptr to 512 byte sector buffer +currside rmb 1 head flag; 0=front 1 = back +u00AE rmb 1 LSB of LSN + IFGT Level-1 +FBlock rmb 2 block number for format +FTask rmb 1 task number for format + ENDC +VIRQPak rmb 2 Vi.Cnt word for VIRQ +u00B3 rmb 2 Vi.Rst word for VIRQ +u00B5 rmb 1 Vi.Stat byte for VIRQ (drive motor timeout) +loglsn rmb 2 OS9's logical sector # +* Removed next line and added two new ones. RG +* PCDOS does not ask driver for any info. +* physlsn rmb 2 PCDOS (512 byte sector) # +flag512 rmb 1 PCDOS (512 byte sector) 0=no, 1=yes +flagform rmb 1 SCII format flag +size equ . + + fcb DIR.+SHARE.+PEXEC.+PWRIT.+PREAD.+EXEC.+UPDAT. + +name fcs /rb1773/ + fcb edition + +VIRQCnt fdb TkPerSec*4 Initial count for VIRQ (4 seconds) + +IRQPkt fcb $00 Normal bits (flip byte) + fcb $01 Bit 1 is interrupt request flag (Mask byte) + fcb 10 Priority byte + +* Init +* +* Entry: +* Y = address of device descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +* New code added 09/03/2003 by Boisy G. Pitre +* Write a pattern to $FF4B and read it back to verify that the hardware +* does exist. +Init equ * +* Two new lines for SCII. RG + IFNE SCII + clr RW.Ctrl clear SCII control register + clr flagform,u clear SCII format flag + ENDC + ldx V.PORT,u get Base port address + lda WD_Data,x get byte at FDC Data register + coma complement it to modify it + sta WD_Data,x write it + clrb +Init2 decb delay a bit... + bmi Init2 + suba WD_Data,x read it back + lbne NoHW if not zero, we didn't read what we wrote +** + IFEQ Level-1 + clr >D.DskTmr flag drive motor as not running + ELSE + clr <D.MotOn flag drive motor as not running + ENDC + leax WD_Stat,x point to Status/Command register + lda #S$FrcInt "Force Interrupt" command + sta ,x send to FDC + lbsr FDCDelay time delay for ~ 108 cycles + lda ,x eat status register + ldd #$FF*256+N.Drives 'invalid' value & # of drives + leax DRVBEG,u point to start of drive tables +l1 sta ,x DD.TOT MSB to bogus value + sta <V.TRAK,x init current track # to bogus value + leax <DRVMEM,x point to next drive table + decb done all drives yet? + bne l1 no, init them all + leax >NMISvc,pc point to NMI service routine + IFGT Level-1 + stx <D.NMI install as system NMI + ELSE + stx >D.XNMI+1 NMI jump vector operand + lda #$7E JMP code + sta >D.XNMI NMI jump vector opcode + ENDC + pshs y save device dsc. ptr + leay >u00B5,u point to Vi.Stat in VIRQ packet + tfr y,d make it the status register ptr for IRQ + leay >IRQSvc,pc point to IRQ service routine + leax >IRQPkt,pc point to IRQ packet + os9 F$IRQ install IRQ + puls y Get back device dsc. ptr + bcs Return If we can't install IRQ, exit + ldd #512 Request 512 byte sector buffer + pshs u Preserve device mem ptr + os9 F$SRqMem Request sector buffer + tfr u,x Move ptr to sector buffer to x + puls u Restore device mem ptr + bcs Return If error, exit with it + stx >sectbuf,u Save ptr to sector buffer + +* GetStat +* +* Entry: +* A = function code +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +GetStat clrb no GetStt calls - return, no error, ignore +Return rts + +* Term +* +* Entry: +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +Term leay >VIRQPak,u Point to VIRQ packet + IFNE H6309 + tfr 0,x "remove" + ELSE + ldx #$0000 + ENDC + os9 F$VIRQ Remove VIRQ + IFNE H6309 + tfr 0,x "remove" + ELSE + ldx #$0000 + ENDC + leay >IRQSvc,pc point to IRQ service routine + os9 F$IRQ Remove IRQ + pshs u Save device mem ptr + ldu >sectbuf,u Get pointer to sector buffer + ldd #512 Return sector buffer memory + os9 F$SRtMem + puls u Restore device mem ptr + clr >DPort+CtrlReg shut off drive motors + IFEQ Level-1 + clr >D.DskTmr Clear out drive motor timeout flag + ELSE + clr <D.MotOn Clear out drive motor timeout flag + ENDC +ex rts return + +* Check if 512 byte sector conversion needed +* Entry: B:X=LSN +* U=Static mem ptr +* Y=Path dsc. ptr +* Exit: X=New LSN (same as original for 256 byte sectors, 1/2 of original +* for 512 byte sectors +* regD changed +Chk512 equ * + clr flag512,u set to 256 byte sector + stx >loglsn,u save OS9 LSN + lda <PD.TYP,y get device type from path dsc. + anda #%00000100 mask out all but 512 byte sector flag + bne Log2Phys 512 byte sectors, go process + rts RG + +* 512 byte sector processing goes here +* regB should be saved and not just cleared at end because there is +* a subsequent tst for the msb of lsn. The test is pointless if B +* is changed. +Log2Phys pshs b save MSB of LSN; new RG +* Minor inefficiencies here that I have changed, RG + tfr x,d + IFNE H6309 + lsrd + ELSE + lsra + rorb + ENDC + tfr d,x move new LSN back to regX +* New line for stock SCII controller with 256 max no-halt. + inc flag512,u set to 512 byte sector + puls b,pc regB will be tested later for >0 + +start lbra Init + bra Read + nop + lbra Write + bra GetStat + nop + lbra SetStat + bra Term + nop + +* Read +* +* Entry: +* B = MSB of LSN +* X = LSB of LSN +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +Read bsr Chk512 go check for 512 byte sector/adjust if needed + lda #%10010001 error flags (see Disto SCII source) + pshs x preserve sector # + lbsr ReadWithRetry go read the sector + puls x restore sector # + bcs ex if error, exit + pshs y,x save path dsc ptr & LSN + leax ,x LSN0?, ie. tstx + bne L012D no, go calculate normally + puls y,x yes, restore path dsc ptr & LSN + lda <PD.TYP,y get type from path dsc. + bita #TYP.NSF standard OS-9 format? + beq L00F0 yes, skip ahead + lbsr MakeDTEntry else make a drive table entry + pshs y,x save path dsc ptr + bra L012D + +* LSN0, standard OS-9 format - copy part of LSN0 into drive table +L00F0 ldx >sectbuf,u Get ptr to sector buffer + pshs y,x Preserve path dsc. ptr & sector buffer ptr + ldy >lastdrv,u Get last drive table accessed ptr + IFNE H6309 + ldw #DD.SIZ # bytes to copy from new LSN0 to drive table + tfm x+,y+ Copy them + ELSE + ldb #DD.SIZ +L00F0Lp lda ,x+ + sta ,y+ + decb + bne L00F0Lp + ENDC + ldy >lastdrv,u Get drive table ptr back + lda <DD.FMT,y Get format for disk in drive + ldy 2,s restore path descriptor pointer + ldb <PD.DNS,y Get path's density settings + bita #FMT.DNS Disk in drive double density? + beq L0115 No, all drives can read single, skip ahead + bitb #DNS.MFM Can our path dsc. handle double density? + beq erbtyp No, illegal +L0115 bita #FMT.TDNS Is new disk 96/135 tpi? + beq L011D No, all drives handle 48 tpi, so skip ahead + bitb #DNS.DTD Can path dsc. handle 96/135 tpi? + beq erbtyp No, illegal +L011D bita #FMT.SIDE Is new disk double sided? + beq L0128 No, all drives handle single sided, we're done + lda <PD.SID,y Get # sides path dsc. can handle + suba #2 sides higher or equal to 2? + blo erbtyp Yes, exit with illegal type error +L0128 clrb No error +* LSN's other than 0 come straight here +L012D ldy 2,s Get path dsc. ptr back?? + ldx PD.BUF,y Get path dsc. buffer ptr +* lda <PD.TYP,y Get path dsc. disk type, RG + ldy >sectbuf,u Get ptr to sector buffer + IFNE H6309 + ldw #256 OS9 sector size (even if physical was 512) + ENDC +* anda #%00000100 Mask out all but 512 byte sector flag, RG +* Next replaces the two lines removed, RG + tst flag512,u Is it a 512 byte sector? + beq L014B If normal sector, just copy it + ldd >loglsn,u Get OS9's LSN (twice of the 'real' 512 sector) + andb #$01 Mask out all but odd/even sector indicator + beq L014B Even, use 1st half of 512 byte sector + IFNE H6309 + addr w,y Odd, bump sector buffer ptr to 2nd half + ELSE + leay 256,y + ENDC +L014B equ * + IFNE H6309 + tfm y+,x+ Copy from physical sector buffer to PD buffer + puls pc,y,x restore path dsc & sector buffer ptrs & return + ELSE + pshs d + clrb +L014BLp lda ,y+ + sta ,x+ + decb + bne L014BLp + puls pc,y,x,d restore path dsc & sector buffer ptrs & return + ENDC + +erbtyp comb + ldb #E$BTyp Error - wrong type error + puls pc,y,x + +********************** +* Read error - retry handler +Retry + bcc ReadWithRetry Normal retry, try reading again + pshs x,d Preserve regs + lbsr sktrk0 Seek to track 0 (attempt to recalibrate) + puls x,d Restore regs & try reading again + + +* Read With Retry: Do read with retries +* +* ENTER reg B,X=working lsn on disk +* Y=path descriptor +* U=driver data +* A=retry sequence mix of read & seek track 0 +* EXIT X,Y,U preserved; D,CC changed +* B=error if any +* CC=error flag +ReadWithRetry + pshs x,d Preserve regs + bsr ReadSector Go read sector + puls x,d Restore regs (A=retry flags) + lbcc L01D7 No error, return + lsra Shift retry flags + bne Retry Still more retries allowed, go do them +* otherwise, final try before we give up +ReadSector + lbsr L02AC Do double-step/precomp etc. if needed, seek + lbcs L01D7 Error somewhere, exit with it +L0176 ldx >sectbuf,u Get physical sector buffer ptr + ldb #S$Read Read sector command + IFNE SCII +* If SCII not hacked for 512 byte no-halt, must use halt for 512b sectors RG + IFEQ SCIIHACK + clra SCII normal mode, normal NMI + tst flag512,u SCII must use halt mode for 512 byte sectors + bne L0176B + ENDC + lda #7 SCII read, buffered mode, masked NMI + bsr L01A1B send commands and wait +* New lines needed because the SCII has error other than OS-9 errors. RG + bcs ngood +* This now becomes a subroutine call. RG +* lbcs L03AF get the errors + lbsr L03AF get the errors + bcc good +ngood rts + IFNE H6309 +good pshs y + ldw #128 set counter + ldy #RW.DAT source of data + IFNE SCIIHACK + tst flag512,u + beq sc2rlp + ldw #256 bump up counter to 512 byte sector + ENDC +* Don't use tfm if no halt important else need orcc #$50 for tfm +* If an interrupt occurs during a tfm transfer, the SCII counter +* will update but the tfm will repeat a byte and lose track. +* If orcc #$50 used, then key presses may be lost even with no-halt +* mode. +sc2rlp ldd ,y read two bytes from SCII + std ,x++ transfer two bytes to system buffer + decw update counter + bne sc2rlp + ELSE +good ldy #128 + IFNE SCIIHACK + tst flag512,u + beq sc2rlp + ldy #256 + ENDC +sc2rlp ldd >RW.DAT + std ,x++ + leay -1,y + bne sc2rlp + ENDC + clrb no errors + puls y,pc + ENDC + +L0176B bsr L01A1 Send to controller & time delay to let it settle +*** Next few lines are commented out for blobstop patches +*L0180 bita >DPort+WD_Stat check status register +* bne L0197 eat it & start reading sector +* leay -1,y bump timeout timer down +* bne L0180 keep trying until it reaches 0 or sector read +* lda >ctlimg,u get current drive settings +* ora #C_MOTOR turn drive motor on +* sta >DPort+CtrlReg send to controller +* puls y,cc restore regs +* lbra L03E0 exit with Read Error +*** Blobstop fixes + stb >DPort+CtrlReg send B to control register + nop allow HALT to take effect + nop + bra L0197 and a bit more time +* Read loop - exited with NMI +* Entry: X=ptr to sector buffer +* B=Control register settings +L0197 lda >DPort+WD_Data get byte from controller + sta ,x+ store into sector buffer +* stb >DPort+CtrlReg drive info + nop -- blobstop fix + bra L0197 Keep reading until sector done + +L01A1 orcc #IntMasks Shut off IRQ & FIRQ +* No-halt mode must enter here, skipping IRQ shutoff. +L01A1B stb >DPort+WD_Cmd Send command + IFNE SCII + sta >RW.Ctrl tell SCII what to do + ENDC +L01A1C ldb #C_DBLDNS+C_MOTOR Double density & motor on + orb >ctlimg,u Merge with current drive settings + stb >DPort+CtrlReg Send to control register + IFNE SCII + tst flagform,u Format uses halt mode + bne s512 + IFEQ SCIIHACK + tst flag512,u SCII uses halt with 512 byte sectors + beq s256 + ELSE + bra s256 + ENDC + ENDC +s512 ldb #C_HALT+C_DBLDNS+C_MOTOR Enable halt, double density & motor on + orb >ctlimg,u Merge that with current drive settings + lbra FDCDelay Time delay to wait for command to settle + IFNE SCII +s256 ldb #4 normal mode, NMI masked + lda #255 time out slices + pshs a,x +SC2tmr1 ldx #1 + lbsr Delay sleep or timer + dec ,s count + beq tmout + tst >RW.Ctrl check status + bmi SC2tmr1 loop on not ready + stb RW.Ctrl clear SCII but don't generate NMI + clrb + puls a,x,pc +tmout stb RW.Ctrl clear SCII buffer counter + lda #$D0 force interrupt + sta DPort+WD_Cmd + comb set carry + puls a,x,pc + ENDC + +* Delay for some number of ticks (1 tick = 1/60 second). +* For a hard delay, we need to delay for 14833 cycles at .89MHz or +* 29666 cycles at 1.78MHz +* Entry: X = number of ticks to delay +Delay + pshs d [5+] [4+] + IFGT Level-1 + ldd <D.Proc [6] [5] process pointer + cmpd <D.SysPrc [is it the system? + beq hardloop [3] [3] + os9 F$Sleep if not system then sleep + puls d,pc [5+] [4+] + ENDC +hardloop tfr x,d we want X in A,B +l1@ equ * + IFEQ Level-1 + ldx #1482/2 [3] [3] + ELSE + IFNE H6309 + ldx #1854 [3] [3] + ELSE + ldx #1482 [3] [3] + ENDC + ENDC +l2@ nop [2] [1] + nop [2] [1] + nop [2] [1] + leax -1,x [4+] [4+] + bne l2@ [3] [3] + subd #$0001 [4] [3] + bne l1@ [3] [3] + puls d,pc [5+] [4+] + +* Write +* Entry: +* B = MSB of LSN +* X = LSB of LSN +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +Write lbsr Chk512 go adjust LSN for 512 byte sector if needed +* Next line was lda #%1001001 which was an error RG + lda #%10010001 retry flags for I/O errors (see Disto SCII source) +L01C4 pshs x,d preserve LSN, retries + bsr L01E8 go write the sector + puls x,d restore LSN, retries + bcs L01D8 error writing, go to write retry handler + tst <PD.VFY,y no error, do we want physical verify? + bne L01D6 no, exit without error + lbsr verify go re-read & verify 64 out of 256 bytes + bcs L01D8 error on verify, go to write retry handler +L01D6 clrb no error & return +L01D7 rts + +* Write error retry handler +L01D8 lsra Shift retry flags + lbeq L03AF Too many retries, exit with error + bcc L01C4 Normal retry, attemp to re-write sector + pshs x,d Preserve flags & sector # + lbsr sktrk0 Seek to track 0 (attempt to recalibrate) + puls x,d Restore flags & sector # + bra L01C4 Try re-writing now + +* 512 byte sector write here +L01E8 lbsr L02AC Go do double-step/write precomp if needed + bcs L01D7 Error, exit with it + pshs y,d Preserve path dsc. ptr & LSN +* Since I have modified chk512 the next two lines are replaced. RG +* lda <PD.TYP,y Get device type +* anda #%00000100 512 byte sector? + tst flag512,u go if 256 byte sectors + beq L020D Not 512 then skip ahead + lbsr L0176 Go read the sector in + ldd >loglsn,u Get OS9 LSN + andb #$01 Even or odd? + beq L020D Even, skip ahead + ldx >sectbuf,u Get physical sector buffer ptr + leax >$0100,x Point to 2nd half + bra L0211 Copy caller's buffer to 2nd half of sector + +L020D ldx >sectbuf,u Get physical sector buffer ptr + +L0211 ldy PD.BUF,y Get path dsc. buffer ptr + IFNE H6309 + ldw #256 Copy write buffer to sector buffer + tfm y+,x+ + ELSE + clrb +L0211Lp lda ,y+ + sta ,x+ + decb + bne L0211Lp + ENDC + puls y,d Get path dsc. ptr & LSN back + ldx >sectbuf,u Get physical sector buffer ptr again +* See read routine for explanation of SCII code. RG + IFNE SCII + IFEQ SCIIHACK + clra SCII write, normal mode & NMI + tst flag512,u + bne wr512 + ENDC + lda #4 SCII normal mode, masked NMI + sta RW.Ctrl tell SCII + pshs y + ldy #RW.Dat Send data to SCII RAM buffer + IFNE H6309 + ldw #128 + tst flag512,u + beq wrbuf + ldw #256 +wrbuf ldd ,x++ + std ,y + decw + bne wrbuf + ELSE + ldy #128 + tst flag512,u + beq wrbuf + ldy #256 +wrbuf ldd ,x++ + std >RW.DAT + leay -1,y + bne wrbuf + ENDC + puls y + ldb #$A0 Write sector command + lda #6 SCII masked NMI, buffered mode, write +* See Read section for explanation of error changes below. RG +* lbra L01A1B send command to controller + lbsr L01A1B send command to controller + bcs wngood SCII error, then go + lbra L03AF check for OS-9 errors +wngood rts + ENDC +wr512 ldb #S$Format + +* Format track comes here with B=$F0 (write track) +* as does write sector with B=$A0 +*WrTrk pshs y,cc Preserve path dsc. ptr & CC +WrTrk lbsr L01A1 Send command to controller (including delay) +*** Commented out for blobstop fixes +*L0229 bita >DPort+WD_Stat Controller done yet? +* bne L0240 Yes, go write sector out +* leay -$01,y No, bump wait counter +* bne L0229 Still more tries, continue +* lda >ctlimg,u Get current drive control register settings +* ora #C_MOTOR Drive motor on (but drive select off) +* sta >DPort+CtrlReg Send to controller +* puls y,cc Restore regs +* lbra L03AF Check for errors from status register + +*** added blobstop + IFGT Level-1 + lda FBlock+1,u get the block number for format + beq L0230 if not format, don't do anything + sta >$FFA1 otherwise map the block in + ENDC +L0230 stb >DPort+CtrlReg send data to control register +* These lines added to match read routine. Should be better timing. RG + nop + nop + bra L0240 wait a bit for HALT to enable + +* Write sector routine (Entry: B= drive/side select) (NMI will break out) +* Part of timing change mentioned above. RG +*L0240 nop --- wait a bit more +L0240 lda ,x+ Get byte from write buffer + sta >DPort+WD_Data Save to FDC's data register +* EAT 2 CYCLES: TC9 ONLY (TRY 1 CYCLE AND SEE HOW IT WORKS) + IFEQ TC9-1 + nop + nop + ELSE +* See above. RG + nop + ENDC +* stb >DPort+CtrlReg Set up to read next byte + bra L0240 Go read it + +* NMI routine +NMISvc leas R$Size,s Eat register stack + IFGT Level-1 + ldx <D.SysDAT get pointer to system DAT image + lda 3,x get block number 1 + sta >$FFA1 map it back into memory + ENDC + andcc #^IntMasks turn IRQ's on again + ldb >DPort+WD_Stat Get status register + IFNE SCII + clr RW.Ctrl Clear SCII command register + ENDC + bitb #%00000100 Did we lose data in the transfer? + lbeq L03B2 Otherwise, check for drive errors + comb -- blobstop error code + ldb #E$DevBsy -- device busy + rts -- and exit + +verify pshs x,d +* Removed unneeded code. Data never sent to PD.BUF anyway so there is +* no need to redirect the PD.BUF pointer. RG +* ldx PD.BUF,y Get write buffer ptr +* pshs x Preserve it +* ldx >sectbuf,u Get sector buffer ptr +* stx PD.BUF,y Save as write buffer ptr +* ldx 4,s + lbsr ReadSector Go read sector we just wrote +* puls x Get original write buffer ptr +* stx PD.BUF,y Restore path dsc. version + bcs L02A3 If error reading, exit with it + ldx PD.BUF,y Get system buffer ptr + pshs u,y Preserve device mem, path dsc. ptrs +* See change in chk512 routine. RG +* ldb <PD.TYP,y Get type from path dsc. + ldy >sectbuf,u Get sector buffer ptr +* andb #%00000100 512 byte sector? + tst flag512,u 512 byte sector? + beq L028D No, skip ahead + ldd >loglsn,u Get OS9's sector # + andb #$01 Odd/even sector? + beq L028D Even; compare first half + leay >$0100,y Odd, compare second half +L028D tfr x,u Move PD.BUF ptr to U (since cmpx is faster) + clra check all 256 bytes +L028F ldx ,u++ Get 2 bytes from original write buffer + cmpx ,y++ Same as corresponding bytes in re-read sector? + bne vfybad No, error & return + inca + bpl L028F No, continue + bra L02A1 carry is clear by virtue of last cmpx +vfybad comb set carry +L02A1 puls u,y +L02A3 puls pc,x,d + +L02A5 pshs a Save Caller's track # + ldb <V.TRAK,x Get track # drive is currently on + bra L02E9 Go save it to controller & continue + +L02AC lbsr L0376 Go set up controller for drive, spin motor up + bsr L032B Get track/sector # (A=Trk, B=Sector) + pshs a Save track # + lda >currside,u Get side 1/2 flag + beq L02C4 Side 1, skip ahead + lda >ctlimg,u Get control register settings + ora #C_SIDSEL Set side 2 (drive 3) select + sta >ctlimg,u Save it back +L02C4 lda <PD.TYP,y Get drive type settings + bita #%00000010 ??? (Base 0/1 for sector #?) + bne L02CC Skip ahead + incb Bump sector # up by 1 +L02CC stb >DPort+WD_Sect Save into Sector register + ldx >lastdrv,u Get last drive table accessed + ldb <V.TRAK,x Get current track # on device + lda <DD.FMT,x Get drive format specs + lsra Shift track & bit densities to match PD + eora <PD.DNS,y Check for differences with path densities + anda #%00000010 Keep only 48 vs. 96/135 tpi differences + pshs a Save differences + lda 1,s Get track # back + tst ,s+ Are tpi's different? + beq L02E9 No, continue normally + lsla Yes, multiply track # by 2 ('double-step') + lslb Multiply current track # by 2 ('double-step') +L02E9 stb >DPort+WD_Trak Save current track # onto controller + +* From here to the line before L0307 is for write precomp, but is not used. +* Unless write precomp is needed, all of this is useless +* I think most (if not all) drives do NOT need precomp + IFEQ PRECOMP-1 + ldb #21 Pre-comp track # + pshs b Save it + ldb <PD.DNS,y Get current density settings + andb #%00000010 Just want to check track density + beq L02F9 48 tpi, skip ahead + lsl ,s Multiply pre-comp value by 2 ('double-step') +L02F9 cmpa ,s+ Is track # high enough to warrant precomp? + bls L0307 No, continue normally + ldb >ctlimg,u + orb #C.WRPCMP Turn on Write precomp + stb >ctlimg,u + ENDC + +L0307 tst >u00AA,u ??? Get flag (same drive flag?) + bne L0314 no, skip ahead + ldb ,s get track # + cmpb <V.TRAK,x same as current track on this drive? + beq L0321 yes, skip ahead +L0314 sta >DPort+WD_Data save track # to data register + ldb <PD.STP,y get stepping rate + andb #%00000011 just keep usable settings (6-30 ms) + eorb #%00011011 set proper bits for controller + lbsr L03E4 send command to controller & time delay +L0321 puls a get track # back + sta <V.TRAK,x save as current track # + sta >DPort+WD_Trak save to controller + clrb no error & return + rts + +* Entry: B:X LSN +* Exit: A=Track # +* B=Sector # +* <currside=00 = Head 1 , $FF = Head 2 +L032B tstb Sector # > 65535? + bne L033F Yes, illegal for floppy + tfr x,d Move sector # to D + leax ,x LSN 0? ie. "tstx" + beq L0371 Yes, exit this routine + ldx >lastdrv,u Get previous drive table ptr + cmpd DD.TOT+1,x Within range of drive spec? + blo L0343 Yes, go calculate track/sector #'s +L033F comb Exit with Bad sector # error + ldb #E$Sect + rts + +* Calculate track/sector #'s? +* These two sections could be combined into one with a final +* test of DD.FMT. Then currside can be set and regA can be lsra +* as needed. RG +L0343 stb >u00AE,u Save LSB of LSN + clr ,-s Clear track # on stack + ldb <DD.FMT,x Get drive format + lsrb Shift out # sides into carry + ldb >u00AE,u Get LSB of LSN again + bcc L0367 Single sided drive, skip ahead + bra L035D Double sided drive, skip ahead +* Double sided drive handling here +L0355 com >currside,u Odd/even sector track flag + bne L035D Odd, so don't bump track # up + inc ,s Bump up track # + +* Changed this to more effient code. RG +*L035D subb DD.TKS,x Subtract # sectors/track +* sbca #$00 +L035D subd DD.SPT,x + bcc L0355 Still more sectors left, continue + bra L036D Wrapped, skip ahead +* Single sided drive handling here +L0365 inc ,s Bump track # up + +* See above. RG +*L0367 subb DD.TKS,x Subtract # sectors/track +* sbca #$00 +L0367 subd DD.SPT,x + bcc L0365 Still more, go bump the track up +* Next possible because upper limit is 256 sectors/track. RG +L036D addb DD.TKS,x Bump sector # back up from negative value + puls a Get the track # +L0371 rts A=track #, B=Sector #, <currside=Odd + +* Drive control register bit mask table +* May want an option here for double sided SDDD disks ex. RG +* fcb $1 drive0 +* fcb $2 drive1 +* fcb $41 drive2 +* fcb $42 drive3 +* fcb $4 drive4 +* fcb $44 drive5 + +L0372 fcb $01 Drive 0 + fcb $02 Drive 1 + fcb $04 Drive 2 + fcb $40 Drive 3 / Side select + +* Changes regD; X,Y,U preserved +L0376 clr >u00AA,u clear drive change flag +chkdrv lda <PD.DRV,y Get drive # requested +* It is possible to have more than 4 drive # so the change below. RG +* cmpa #4 Drive 0-3? + cmpa #N.Drives Drive 0-6 if alternate table used? + blo L0385 Yes, continue normally +NoHW comb Illegal drive # error + ldb #E$Unit + rts + +* Entry: A=drive #, X=LSN (Physical, not OS9 logical if PCDOS disk) +L0385 pshs x,d Save sector #, drive # & B??? + leax >L0372,pc Point to drive bit mask table + ldb a,x Get bit mask for drive # we want + stb >ctlimg,u Save mask + leax DRVBEG,u Point to beginning of drive tables + ldb #DRVMEM Get size of each drive table + mul Calculate offset to drive table we want + leax d,x Point to it + cmpx >lastdrv,u Same as Last drive table accessed? + beq L03A6 Yes, skip ahead + stx >lastdrv,u Save new drive table ptr + com >u00AA,u Set drive change flag +L03A6 clr >currside,u Set side (head) flag to side 1 + lbsr L04B3 Go set up VIRQ to wait for drive motor + puls pc,x,d Restore sector #,drive #,B & return + +L03AF ldb >DPort+WD_Stat Get status register from FDC +* This line needed when returning to Disk Basic but probably +* not needed for OS-9. RG + IFNE SCII + clr RW.Ctrl return SCII to halt mode + ENDC +L03B2 bitb #%11111000 any of the error bits set? + beq L03CA No, exit without error + aslb Drive not ready? + bcs L03CC Yes, use that error code + aslb Write protect error? + bcs L03D0 Yes, use that error code + aslb Write fault error? + bcs L03D4 Yes, use that error code + aslb Sector not found? + bcs L03D8 Yes, use Seek error code + aslb CRC error? + bcs L03DC Yes, use that error code +L03CA clrb No error & return + rts + +L03CC ldb #E$NotRdy not ready + fcb $8C skip 2 bytes + +L03D0 ldb #E$WP write protect + fcb $8C skip 2 bytes + +L03D4 ldb #E$Write write error + fcb $8C + +L03D8 ldb #E$Seek seek error + fcb $8C + +L03DC ldb #E$CRC CRC error +* fcb $8C + +*L03E0 ldb #E$Read Read error + orcc #Carry set carry + rts + +L03E4 bsr L0404 Send command to controller & waste some time +L03E6 ldb >DPort+WD_Stat Check FDC status register + bitb #$01 Is controller still busy? + beq L0403 No, exit + ldd >VIRQCnt,pc Get initial count value for drive motor speed + std >VIRQPak,u Save it +* Again, I'm trying to match Kevin Darling code. It may not be needed. RG + pshs x + ldx #1 Sleep remainder of slice + lbsr Delay + puls x + bra L03E6 Wait for controller to finish previous command + +* Send command to FDC +L03F7 lda #C_MOTOR +* lda #%00001000 Mask in Drive motor on bit + ora >ctlimg,u Merge in drive/side selects + sta >DPort+CtrlReg Turn the drive motor on & select drive + stb >DPort+WD_Cmd Save command & return +L0403 rts + +L0404 bsr L03F7 Go send command to controller + +* This loop has been changed from nested LBSRs to timing loop. +* People with crystal upgrades should modify the loop counter +* to get a 58+ us delay time. MINIMUM 58us. +FDCDelay + pshs a 14 cycles, plus 3*loop counter + IFEQ Level-1 + lda #18 (only do about a 100 cycle delay for now) + ELSE + lda #29 (only do about a 100 cycle delay for now) + ENDC +L0409 deca for total ~63 us delay (123 cycles max.) + bne L0409 + puls a,pc restore register and exit + +* SetStat +* +* Entry: +* A = function code +* Y = address of path descriptor +* U = address of device memory area +* +* Exit: +* CC = carry set on error +* B = error code +* +SetStat ldx PD.RGS,y Get caller's register stack ptr + ldb R$B,x Get function code + cmpb #SS.WTrk Write track? + beq SSWTrk Yes, go do it + cmpb #SS.Reset Restore head to track 0? + lbeq sktrk0 Yes, go do it --- beq + comb set carry for error + ldb #E$UnkSvc return illegal service request error + rts + +SSWTrk pshs u,y preserve register stack & descriptor + +* Level 2 Code + IFGT Level-1 + +*--- new code + ldb #1 1 block to allocate + os9 F$AllRAM allocate some RAM + lbcs L0489 error out if at all + leax >FBlock,u point to 'my' DAT image + std ,x save a copy of the block + os9 F$ResTsk reserve a task number for the copy + bcs FError error out + stb 2,x save temporary task number in FTask,u + lslb 2 bytes per entry + ldu <D.TskIPt get task image table pointer + stx b,u save pointer to the task's DAT image + lsrb get the right number again + IFNE H6309 + tfr 0,u destination is address 0 + ELSE + ldu #$0000 + ENDC +*--- end new code + + ldx 2,s get pointer to descriptor +* stu >FBlock,x + ldx <D.Proc Get current process ptr + lda P$Task,x Get task # for current process +* ldb <D.SysTsk Get system task # + ldy ,s + ldx PD.RGS,y Get register stack ptr + ldx R$X,x Get ptr to caller's track buffer + ldy #$1A00 Size of track buffer + os9 F$Move Copy from caller to temporary task + bcs L0479 Error copying, exit + puls u,y + pshs u,y + + ENDC +* End of Level 2 Code + + lbsr L0376 Go check drive #/wait for it to spin up + ldx PD.RGS,y Get caller's register stack ptr + ldb R$Y+1,x Get caller's side/density + bitb #$01 Check side + beq L0465 Side 1, skip ahead +* I think this next line is not needed. RG + com >currside,u * Why? This is normally used with +* calculate track. RG + ldb >ctlimg,u Get current control register settings +* orb #%01000000 Mask in side 2 + orb #C_SIDSEL Mask in side 2 + stb >ctlimg,u Save updated control register +L0465 lda R$U+1,x Get caller's track # + ldx >lastdrv,u Get current drive table ptr + lbsr L02A5 + bcs L0489 + ldb #$F0 Write track command +*--- + IFEQ Level-1 + ldx PD.RGS,y + ldx R$X,x + ELSE + ldx #$2000 start writing from block 1 + ENDC + + IFNE SCII + lda #1 normal unbuffered write +* Next line prevents WrTrk from switching to SCII buffered mode. RG + sta flagform,u + ENDC + lbsr WrTrk Go write the track + IFNE SCII + clr flagform,u permit no-halt mode RG + ENDC + + IFGT Level-1 +L0479 ldu 2,s + pshs b,cc Preserve error + ldb >FTask,u point to task + os9 F$RelTsk release the task + fcb $8C skip 2 bytes + +* format comes here when block allocation passes, but task allocation +* gives error. So er de-allocate the block. +FError + pshs b,cc save error code, cc + ldx >FBlock,u point to block + ldb #1 1 block to return + os9 F$DelRAM de-allocate image RAM blocks + clr FBlock+1,u ensure that the block # in FBlock is zero. + puls b,cc Restore error + ENDC + +L0489 puls pc,u,y Restore regs & return + +* seek the head to track 0 +sktrk0 lbsr chkdrv + ldx >lastdrv,u + clr <$15,x + lda #1 was 5 but that causes head banging +L0497 ldb <PD.STP,y + andb #%00000011 Just keep usable settings (6-30 ms) + eorb #%01001011 Set proper bits for controller + pshs a + lbsr L03E4 + puls a + deca + bne L0497 + ldb <PD.STP,y + andb #%00000011 Just keep usable settings (6-30 ms) + eorb #%00001011 Set proper bits for controller + lbra L03E4 + +L04B3 pshs y,x,d Preserve regs + ldd >VIRQCnt,pc Get VIRQ initial count value + std >VIRQPak,u Save it + lda >ctlimg,u ?Get drive? + ora #C_MOTOR Turn drive motor on for that drive +* ora #%00001000 Turn drive motor on for that drive + sta >DPort+CtrlReg Send drive motor on command to FDC + IFEQ Level-1 + lda >D.DskTmr Get VIRQ flag + ELSE + lda <D.MotOn Get VIRQ flag + ENDC + bmi L04DE Not installed yet, try installing it + bne L04E0 Drive already up to speed, exit without error + +* Drive motor speed timing loop (could be F$Sleep call now) (was over .5 sec) +* 32 was not sufficient for one of my drives. RG + ldx #50 wait for 32 ticks; increased it RG + lbsr Delay + +L04DE bsr InsVIRQ Install VIRQ to wait for drive motors +L04E0 clrb No error & return + puls pc,y,x,d + +InsVIRQ lda #$01 Flag drive motor is up to speed + IFEQ Level-1 + sta >D.DskTmr + ELSE + sta <D.MotOn + ENDC + ldx #$0001 Install VIRQ entry + leay >VIRQPak,u Point to packet + clr Vi.Stat,y Reset Status byte + ldd >VIRQCnt,pc Get initial VIRQ count value + os9 F$VIRQ Install VIRQ + bcc VIRQOut No error, exit + lda #$80 Flag that VIRQ wasn't installed + IFEQ Level-1 + sta >D.DskTmr + ELSE + sta <D.MotOn + ENDC +VIRQOut clra + rts + +* IRQ service routine for VIRQ (drive motor time) +* Entry: U=Ptr to VIRQ memory area +IRQSvc pshs a + lda <D.DMAReq + beq L0509 + bsr InsVIRQ + bra IRQOut +L0509 sta >DPort+CtrlReg +* I changed this to a clear. Don't see the point of an AND. RG +* IFNE H6309 +* aim #$FE,>u00B5,u +* ELSE +* lda u00B5,u +* anda #$FE +* sta u00B5,u +* ENDC +* fdb u00B5 --- so changes in data size won't affect anything + clr u00B5,u + IFEQ Level-1 + clr >D.DskTmr + ELSE + clr <D.MotOn + ENDC +IRQOut puls pc,a + +* Non-OS9 formatted floppies need a drive table entry constructed +* by hand since there is no RBF LSN0. +* +* Entry: X=LSN +* Y=Path dsc. ptr +* U=Device mem ptr +MakeDTEntry + pshs x Preserve Logical sector # + ldx >lastdrv,u Get last drive table accessed ptr + clra + pshs x,a Save ptr & NUL byte + IFNE H6309 + ldw #20 Clear 20 bytes + tfm s,x+ + ELSE + ldb #20 +L051ALp clr ,x+ + decb + bne L051ALp + ENDC + puls x,a Eat NUL & get back drive table ptr + ldb <PD.CYL+1,y Get # cylinders on drive (ignores high byte) + lda <PD.SID,y Get # sides + mul Calculate # tracks on drive (1 per head) + IFNE H6309 + decd Adjust to ignore track 0 + ELSE + subd #$0001 + ENDC + lda <PD.SCT+1,y Get # sectors/track + sta DD.TKS,x Save in drive table + sta <DD.SPT+1,x Save in other copy in drive table + mul Calculate # sectors on drive (minus track 0) + pshs x Preserve drive table ptr + tfr d,x Move # sectors on drive to X + lda <PD.T0S+1,y Get # sectors on track 0 + leax a,x Add that many sectors to total + lda <PD.TYP,y Get device type settings + anda #%00000100 Mask out all but 512 byte sector flag + beq L0550 Not 512 byte sector, skip ahead + IFNE H6309 + addr x,x Multiply by 2 (convert to 256 byte OS9 sectors) + ELSE + tfr x,d + leax d,x + ENDC +L0550 tfr x,d Move # sectors to D + puls x Get back drive table ptr + std DD.TOT+1,x Save # sectors allowed on drive + lda #UPDAT.+EXEC. Owner's read/write/exec attributes + sta DD.ATT,x Set attributes for disk + lda <PD.DNS,y Get density settings + lsla Shift for DD.FMT + pshs a Preserve it a sec + lda <PD.SID,y Get # sides + deca Adjust to base 0 + ora ,s+ Merge with density settings + sta <DD.FMT,x Save in device table + clrb No error? + puls pc,x Restore original LSN & return + + emod +eom equ * + end +