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
+