view level1/modules/rbsuper.asm @ 2730:6bd6e348665d

Working on cloned default branch, pulled 2012/11/03 user: gheskett@wdtv.com branch 'default' changed ChangeLog changed ReadMe changed defs/rbf.d changed defs/rbsuper.d changed defs/scsi.d changed level1/atari/cmds/fuji.asm changed level1/coco/modules/makefile changed level1/modules/boot_scsi.asm changed level1/modules/superdesc.asm changed level2/coco3/bootfiles/makefile changed level2/coco3/modules/makefile changed level2/coco3_6309/bootfiles/makefile changed level2/modules/joydrv_6551L.asm changed rules.mak
author gheskett@wdtv.com
date Sat, 10 Nov 2012 11:55:48 -0500
parents 17d43fd29ee2
children ebf319736e9c
line wrap: on
line source

********************************************************************
* rbsuper - RBF Super Caching Device Driver
*
* $Id$
*
* (C) 2004 Boisy G. Pitre - Licensed to Cloud-9
*
* RBSuper is the framework for a new type of RBF device driver -- one
* that fetches native-size, or PHYSICAL sectors.  A physical sector is
* a sector that is sized to its device.  For example, all IDE drives and
* pretty much all SCSI drives have 512 byte sectors; CD-ROMs have 2048
* byte sectors.
*
* As a high-level driver, this module is responsible for managing
* the cache, verifying writes, etc.
*
* The actual reading and writing of sectors is performed by the
* low-level driver, which can be designed for any device.
*
* Conditionals:
*   H6309 - if set, assembles for 6309
*   USECS - if set, uses critical section code (slows down driver)
*   HDBDOS - if set, adds code to handle HDB-DOS partitions
*
* Edt/Rev  YYYY/MM/DD  Modified by
* Comment
* ------------------------------------------------------------------
*          2004/04/10  Boisy G. Pitre
* Created due to Mark's constant harping about a NitrOS-9 driver for
* the SuperIDE Interface.  Here ya go, Marlette.
*
*          2005/12/12  Boisy G. Pitre
* The SS.VarSect call has been moved from the low level driver to rbsuper
* for efficiency.  Also it no longer calls SS.DSize every time it is called.
* Instead, it only calls it the first time, then caches the sector size value
* and returns that value on subsequent calls.
*
*          2005/12/13  Boisy G. Pitre
* Employed a trick to "shift" the idea of where the driver's static
* data starts at the start of each entry point.  This saves about 200
* bytes of memory.
*
* 1        2006/08/20  Boisy G. Pitre
* Fixed bug where linking to a non-existent module in Init would cause a crash
* because IOMan calls the Term routine when Init returns an error.  Added a simple
* one line test in Term to see if a value was non-zero which would indicate if Init
*
* 2        2008/02/05  Boisy G. Pitre
* Fixed bug where DNS HDB flag was being pulled from PD.TYP byte instead of PD.DNS.
*
* 3        2011/12/22  Boisy G. Pitre
* Made a "fast path" for 256 byte sector devices to read/write directly into PD.BUF
* instead of using the cache, for performance reasons.
* Conditionalized critical section code since it may not be needed, and affects performance.

               NAM       rbsuper             
               TTL       RBF Super Caching Device Driver

               IFP1      
               USE       defsfile
               USE       rbsuper.d
               ENDC      

tylg           SET       Drivr+Objct
atrv           SET       ReEnt+rev
rev            SET       0
edition        SET       2

               MOD       eom,name,tylg,atrv,start,V.RBSuper

               FCB       DIR.+SHARE.+PEXEC.+PREAD.+PWRIT.+EXEC.+UPDAT.

name           FCS       /RBSuper/
               FCB       edition

start          lbra      Init
               bra       Read
               nop       
               lbra      Write
               lbra      GetStat
               lbra      SetStat

*
* Term
*
* Entry:
*    U  = address of device memory area
* 
* Exit:
*    CC = carry set on error
*    B  = error code
* 
Term           leau      UOFFSET,u
* Free memory allocated for cache
               lda       V.CchSize,u         get cache size into A
* Note, the next line fixes a bug where the system would crash when F$Link in Init failed.
* If it fails, V.CchSize will never get set, and since it is set to 0 initally, we assume
* that init failed if V.CchSize is 0 and thus we simply return.
               beq       ret@
               tfr       u,x                 move statics ptr into X for safety
               ldu       V.CchAddr,u         and load U with cache address
               beq       nofree@
               os9       F$SRtMem            return cache memory to system
nofree@        tfr       x,u                 and restore statics ptr
* Call low-level driver term
               ldx       V.LLTerm,u
               lbsr      LLCall
* Unlink low-level driver
               IFGT      Level-1
               ldx       D.Proc              get curr proc ptr
               ldd       D.SysPrc            get system process desc ptr
               std       D.Proc              and make current proc
               ENDC      
               ldu       V.LLAddr,u          get the address of the low-level module
               os9       F$Unlink            unlink it
               IFGT      Level-1
               stx       D.Proc              restore
               ENDC      
ret@           rts                           return

*
* Read
*
* Entry:
*    B  = MSB of the disk's LSN
*    X  = LSB of the disk's LSN
*    Y  = address of path descriptor
*    U  = address of device memory area
*
* Exit:
*    CC = carry set on error
*    B  = error code
*
Read           leau      UOFFSET,u
               cmpx      #$0000              LSN 0?
               bne       ReadSect            branch if not
               tstb                          LSN 0?
               bne       ReadSect            branch if not
               bsr       ReadSect            else read LSN0
               bcs       bye                 if error, return
* Code to deal with copying LSN0
               leax      DRVBEG-UOFFSET,u    point X to start of drive table
               ldb       PD.DRV,y            get drive number
lsn@           beq       CopyLSN0            branch if zero
               leax      DRVMEM,x            else increase X by drive table size
               decb                          decrement drive number
               bra       lsn@                branch to loop

* X = drive table pointer for PD.DRV
* Copy DD.SIZ bytes (LSN0) from buffer to drive table
CopyLSN0       EQU       *
               ldu       PD.BUF,y
               IFNE      H6309
               ldw       #DD.SIZ
               tfm       u+,x+
               ELSE      
               ldb       #DD.SIZ
CpyLSNLp       pulu      a                   one cycle less than lda ,u+
               sta       ,x+
               decb      
               bne       CpyLSNLp
               ENDC      
rret           rts       

               IFNE      HDBDOS
* For HDB-DOS, we must add in drive number
* First, multiply drive number in descriptor by $276 (630 sectors),
* then, add the product to the PSect
ComputeHDB               
               IFNE      H6309
               clra      
               ldb       V.HDBDrive,u
               muld      #$0276
               addw      V.PhysSect+1,u
               stw       V.PhysSect+1,u
               adcb      V.PhysSect,u
               stb       V.PhysSect,u
               ELSE      
               leas      -4,s                make a stack to store product of $276 * DriveNum
               lda       V.HDBDrive,u        get drive number
               ldb       #$76
               mul       
               std       2,s
               lda       V.HDBDrive,u
               ldb       #$02
               mul       
               std       ,s
               clrb      
               lda       1,s
               addd      2,s
               std       2,s
               bcc       f@
               inc       ,s
f@             lda       ,s
               sta       1,s
               ldd       2,s
               addd      V.PhysSect+1,u
               std       V.PhysSect+1,u
               lda       1,s
               adca      V.PhysSect,u
               sta       V.PhysSect,u
               leas      4,s
               ENDC      
               ENDC      
bye            rts       

* 256 byte sector device: setup for low level driver to put 256 byte sector directly into PD.BUF
Read256
               lbsr      Log2Phys
* We may not have to do this (and disturb the cache as a result)
*               lda       PD.DRV,y            get current drive number
*               sta       V.LastDrv,u         and make this the current drive
               lda       #1
               sta       V.SectCnt,u
               ldx       PD.BUF,y             put address of PD.BUF directly into cache spot
               stx       V.CchPSpot,u
* Call low-level driver read
               ldx       V.LLRead,u
               lbra      LLCall

* Read Sector
*
* The sector will be read from either the cache or the controller.
* A cache "hit" is verified by two methods:
* 1. Comparing the drive number of the drive for the current path to
*    the drive number of the last path -- if they match, we *MAY*
*    have a cache hit.  If not, we fill the cache
* 2. If #1 matches, then we know the current drive and the last drive
*    are the same.  We then check the logical sector to see if it is
*    in the cache.
*
* Entry:
*    Y = address of path descriptor
*    U = address of device memory area
*    B = Sector bits 23-16
*    X = Sector bits 15-0
*
ReadSect       bsr       PreXfr              to pre-transfer stuff
               bcs       bye                 branch if error
               IFNE      HDBDOS
               tst       V.HDBPart,u         HDB-DOS partition?
               beq       NotHDB
* This is the HDB-DOS partition "read" code path.
* As an HDB-DOS partition, we are interested ONLY in reading the first 256 bytes
* regardless of the size of the cache.
               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,etc)
               leax      SCTTBL,pcr
               lda       a,x
               sta       V.Log2Phys,u        set logical sectors per phys
               lda       #$01                get sector count
               sta       V.SectCnt,u         and store it
               sta       V.CchDirty,u        the cache will ALWAYS be dirty in HDB-DOS mode
               lda       V.LogSect,u         get logical sector stored earlier
               sta       V.PhysSect,u        save off logical sector as physical one
               ldd       V.LogSect+1,u       get logical sector stored earlier
               std       V.PhysSect+1,u      save off logical sector as physical sector
               lbsr      AddSectorOffset     add in partition offset and HDB-DOS drive
               bsr       ComputeHDB          and compute HDB-DOS offset
* Set up the pointer to the buffer
               ldx       V.CchAddr,u         get address of cache
               stx       V.CchPSpot,u        save in current sector pointer
* Call low-level driver
               ldx       V.LLRead,u
               lbsr      LLCall
               bcs       bye
               ldx       V.CchAddr,u         get cache pointer which holds HDB-DOS sector
               bra       CopyXToPDBUF
               ENDC      
NotHDB
* New: Dec 20, 2011
* Fast path opportunity: if sector size is 256 bytes, call LLRead right into PD.BUF
               tst       V.SectSize,u        (0=256 byte sector device)
               beq       Read256 
               bsr       ValidateCache
               bcs       ex@
* Copy appropriate 256 byte sector from V.CchAddr to PD.BUF,y
               lda       V.CchSize,u         get hi byte of cache size
               deca      
               anda      V.LogSect+2,u
               clrb      
               ldx       V.CchAddr,u
               leax      d,x
CopyXToPDBUF   pshs      y
               ldy       PD.BUF,y
               IFNE      H6309
               ldw       #256
               tfm       x+,y+
               clrb      
               puls      y,pc
               ELSE      
               clr       ,-s
next@          ldd       ,x++
               std       ,y++
               inc       ,s
               bpl       next@
               clrb      
               puls      a,y,pc
               ENDC      
ex@            rts       

* ValidateCache
*
* Check if the cache is coherent (i.e. contains requested sector).
* If the cache is NOT coherent, it calls 'FillCache' to fill it.
ValidateCache            
* We must determine if the currently requested sector is already in cache.
* First, is this drive the same as the last drive that accessed the cache?
* If not, then we need to fill the cache with sectors from the current drive.
               tst       V.CchDirty,u        has cache been initialized?
               bne       nomatch             branch if not
               lda       PD.DRV,y            get current drive
               cmpa      V.LastDrv,u         save as last drive to access cache?
               bne       nomatch             if not, fill cache
* Same drive as last access... is this sector in cache?
               ldb       V.LogSect,u         save off logical sector
               cmpb      V.CchBase,u         compare bits 23-16
               bne       nomatch             branch if not the same
               lda       V.LogSect+1,u       save off logical sector
               ldb       V.CchSize,u         get hi byte of cache size
               decb                          decrement (e.g. 8=7,4=3,2=1,1=0)
               comb                          invert (e.g. 7=$F8,3=$FC,1=$FE,0=$FF)
               andb      V.LogSect+2,u       mask out cached sectors
               cmpd      V.CchBase+1,u       same as what's in cache?
               beq       exok@               YES, WE HAVE A CACHE HIT!!!
nomatch        bra       FillCache           no, we must fil the cache
*
* PreXfr
*
* Called at read/write to gather info from path descriptor and
* device descriptor.
PreXfr         stb       V.LogSect,u         save off logical sector
               stx       V.LogSect+1,u       save off logical sector
               lda       PD.STP,y            get possible HDB-DOS drive number
               sta       V.HDBDrive,u        save off in our statics
               lda       PD.TYP,y
               anda      #TYPH.SSM           lob off all but sector size bits
* SmartCache - check if our current cache can accommodate this sector size
               cmpa      V.SectSize,u        do we need to expand?
               bls       no@                 branch if not
* Yes, we need to free our current cache mem and alloc more
               pshs      a,u                 save regs
               ldd       V.CchSize,u         get current cache size
               ldu       V.CchAddr,u         and cache pointer
               beq       nofree@
               os9       F$SRtMem            return that memory
nofree@        puls      a,u                 restore regs
               lbsr      ExpandCache         go expand cache
               bcs       ex@                 and branch if error
               sta       V.SectSize,u        save new sector size
no@
               lda       PD.DNS,y            get DNS byte
               anda      #DNS.HDB            isolate HDB-DOS flag
               sta       V.HDBPart,u         and save state
exok@          clrb                          clear carry
               rts                           return
ex@            clr       V.SectSize,u        clear sector size to force realloc
               orcc      #Carry              set carry (indicates error)
               rts                           return

* FillCache
*
* Fill the cache with sectors from the device.
*
* Destroys: A, B, X
FillCache                
               lda       V.LogSect,u         get logical sector bits 23-16
               sta       V.CchBase,u         save as cached base
               lda       V.LogSect+1,u       save off logical sector
               ldb       V.CchSize,u         get hi byte of cache size (1, 2, 4 or 8)
               decb                          decrement (e.g. 8=7,4=3,2=1,1=0)
               comb                          invert (e.g. 7=$F8,3=$FC,1=$FE,0=$FF)
               andb      V.LogSect+2,u       mask out cached sectors
               std       V.CchBase+1,u       save as cached base
               lbsr      Log2Phys            convert logical sectors to physical
               lda       PD.DRV,y            get current drive number
               sta       V.LastDrv,u         and make this the currently cached drive
* Set up the transfer
               ldb       V.CchSize,u         get upper 8 bits of cache size
               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,etc)
               leax      SCTTBL,pcr
               lda       a,x
               sta       V.Log2Phys,u
               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,etc)
               beq       ok@
lsr@           lsrb                          divide by 2
               deca                          decrement
               bne       lsr@                else divide again
ok@            stb       V.SectCnt,u         save sector count
               decb      
               comb      
               andb      V.PhysSect+2,u
               stb       V.PhysSect+2,u
* Set up the pointer to the buffer
               ldx       V.CchAddr,u         get pointer to big buffer
               stx       V.CchPSpot,u        save in current sector pointer
* Call low-level driver read
               ldx       V.LLRead,u
               bsr       LLCall
               bcs       ex@
               clr       V.CchDirty,u        cache is no longer dirty
               clrb      
               rts       
ex@            stb       V.CchDirty,u        store error code as dirty flag
               rts       


SCTTBL         FCB       256/256
               FCB       512/256
               FCB       1024/256
               FCB       2048/256

* GetStat/SetStat
*
* Entry:
*    R$B = function code
*    Y   = address of path descriptor
*    U   = address of device memory area
*
* Exit:
*    CC = carry set on error
*    B  = error code
*
SetStat        leau      UOFFSET,u
               ldx       V.LLStSt,u
               bra       LLCall

SSVarSect      ldb       PD.DRV,y            get drive number
               leax      V.SSCache,u         point to sector size cache table
               abx       
               lda       ,x                  get sector size
               bne       go2@                if not zero, use that value
               pshs      x
               ldx       PD.RGS,y
               pshs      x
               leas      -R$Size,s
               sts       PD.RGS,y
               lda       #SS.DSize
               sta       R$B,s
               bsr       gs2                 make a call to low level driver's SS.DSize
* Be sure that no instructions from here to the bcs modify carry
               lda       R$A,s
               leas      R$Size,s
               puls      x
               stx       PD.RGS,y
               puls      x
               bcs       ex@
               cmpa      #8                  2048 byte sector?
               beq       go@
               lsra                          else shift right
               FCB       $8C                 skip next two bytes (cmpx...)
go@            lda       #3
               sta       ,x                  save newly acquired value off into cached size table
go2@           pshs      a
               lda       PD.TYP,y
               anda      #^TYPH.SSM
               ora       ,s+
* Boisy's Notes 3/27/06:
* Notice that we save the true sector size of the device in the PD.TYP byte of
* the path descriptor EACH TIME SS.VarSect is called.  This is important,
* because it alleviates the user from having to set this value in the device
* descriptor in a situation where the device being accessed has a larger sector
* size than what is in the device descriptor.
*
* Note that the value in the device descriptor IS used to initially determine
* the size of the cache at INIT time since we haven't even talked to the
* controller at that time yet to query it for its size.
*               sta       PD.TYP,y            and in path descriptor
               clrb      
ex@            rts       


GetStat        leau      UOFFSET,u
               ldx       PD.RGS,y            get registers
               ldb       R$B,x               get caller's B
               cmpb      #SS.VarSect
               beq       SSVarSect

gs2            ldx       V.LLGtSt,u

* Entry: Y = path desc ptr
*        U = statics ptr
*        X = address of routine to call
LLCall
               IFEQ      USECS-1
               pshs      a                   preserve A for duration of csacq_wait
               lda       #255                wait the maximum number of counts
               bsr       csacq_wait          acquire the critical section
               tsta                          test A for zero
               puls      a                   restore A
               beq       cserr               return if A was zero (semaphore wasn't acquired)
               ENDC
               pshs      u,y                 save U and Y
               jsr       ,x                  call low level routine
               puls      y,u                 restore U and Y

               IFEQ      USECS-1
* Critical Section Release - clear the critial section to zero, allowing others to use it
csrel          pshs      cc                  preserve CC
               clr       V.LLSema,u          clear critical section
               puls      cc,pc               restore CC and return
cserr          comb                          set the carry
               ldb       #111                and load B with error indicating a semaphore timeout
               ENDC
               rts       

               IFEQ      USECS-1
* Critical Section Acquire With Wait
*
* Entry:
*    A = number of times to check before giving up
*
* Exit:
*    A = status (>0 = Critical section acquired, 0 = Critical section not acquired)
*
csacq_wait     pshs      cc                  save CC on stack
               orcc      #IntMasks           mask interrupts
               tst       V.LLSema,u          does someone already have the critical section?
               bne       w@                  if so, then branch
               inc       V.LLSema,u          else claim critical section (0->1)
e@             puls      cc,pc               restore CC and return
w@             deca                          decrement our timeout counter
               beq       e@                  if zero, we've timed out, return
               puls      cc                  give interrupts a chance to breathe
               IFGT      Level-1
* Give up timeslice unless this is the system
               pshs      x
               ldx       D.Proc              get proc descriptor
               cmpx      D.SysPrc            system?
               beq       wd@                 yep, system cannot sleep
*               ldx       D.AProcQ            get active proc queue
*               beq       wd@                 if empty, return
               ldx       #$0001
               os9       F$Sleep             give up timeslice
wd@            puls      x                   return to caller
               ENDC      
               bra       csacq_wait          and try again
               ENDC


* Log2Phys - Convert logical sector to physical sector
*
* Stores V.PhysSect,u from V.LogSect,u based on V.SectSize,u
* Also adds IT.SOFF1-IT.SOFF3 to V.PhysSect,u for partitioning.
* Results are placed in V.PhysSect,u
Log2Phys       lda       V.LogSect,u
               sta       V.PhysSect,u
               ldd       V.LogSect+1,u
               std       V.PhysSect+1,u
               lda       V.SectSize,u
               beq       AddSectorOffset
DivBy2         lsr       V.PhysSect,u
               ror       V.PhysSect+1,u
               ror       V.PhysSect+2,u
               deca      
               bne       DivBy2
* This routine adds the 3 byte sector offset in the
* device descriptor to the physical sector.
AddSectorOffset           
               ldx       PD.DEV,y
               ldx       V$DESC,x
               ldd       IT.SOFF2,x
               addd      V.PhysSect+1,u
               std       V.PhysSect+1,u
               lda       IT.SOFF1,x
               adca      V.PhysSect,u
               sta       V.PhysSect,u
logex          rts       


* 256 byte sector device: setup for low level driver to put 256 byte sector directly into PD.BUF
Write256
               bsr      Log2Phys
* We may not have to do this (and disturb the cache as a result)
*               lda       PD.DRV,y            get current drive number
*               sta       V.LastDrv,u         and make this the current drive
               lda       #1
               sta       V.SectCnt,u
               ldx       PD.BUF,y             put address of PD.BUF directly into cache spot
               stx       V.CchPSpot,u
* Call low-level driver read
               ldx       V.LLWrite,u
               bra       LLCall

* Write
*
* Entry:
*    B  = MSB of the disk's LSN
*    X  = LSB of the disk's LSN
*    Y  = address of path descriptor
*    U  = address of device memory area
*
* Exit:
*    CC = carry set on error
*    B  = error code
*
Write          leau      UOFFSET,u
               lbsr      PreXfr              to pre-transfer stuff
               bcs       logex               branch if error
               IFNE      HDBDOS
               lda       V.HDBPart,u         HDB-DOS partition?
               beq       h@
* HDB-DOS partition code path
               sta       V.CchDirty,u        cache is dirty
               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,3=2048)
               leax      SCTTBL,pcr
               lda       a,x
               sta       V.Log2Phys,u        set logical sectors per phys
               lda       V.LogSect,u
               sta       V.PhysSect,u
               ldd       V.LogSect+1,u
               std       V.PhysSect+1,u
               bsr       AddSectorOffset     add in partition offset and HDB-DOS drive
               lbsr      ComputeHDB          and compute HDB-DOS offset
               ldx       PD.BUF,y            get path desc buffer
               stx       V.CchPSpot,u        we write directly from PD.BUF
               bra       writeit
               ENDC      
* New: Dec 20, 2011
* Fast path opportunity: if sector size is 256 bytes, call LLRead right into PD.BUF
h@
               tst       V.SectSize,u        (0=256 byte sector device)
               beq       Write256
               lbsr      ValidateCache
               bcs       logex
* Copy appropriate 256 byte sector from PD.BUF,y to V.CchAddr,u
* Determine where in the cache we copy this 256 byte sector
               bsr       Log2Phys            compute physical sector from logical sector
               lda       V.CchSize,u         get hi byte of cache size
               deca      
               anda      V.LogSect+2,u
               clrb      
               ldx       V.CchAddr,u
               leax      d,x
               stx       V.CchLSpot,u        save for possible verify later
               pshs      y                   save path desc for now
               ldy       PD.BUF,y
               IFNE      H6309
               ldw       #256
               tfm       y+,x+
               puls      y
               ELSE      
               clr       ,-s
loop@          ldd       ,y++
               std       ,x++
               inc       ,s
               bpl       loop@
               puls      a,y
               ENDC      
* Now that sector is copied, determine where in cache we start
               lda       V.LogSect+2,u       get logical sector bits 7-0
               leax      MASKTBL,pcr         point to base of cache
               ldb       V.SectSize,u        get sector size in B
               anda      b,x
               pshs      a
               lda       V.CchSize,u         get upper 8 bits of cache size
               deca      
               anda      ,s+
               clrb      
               ldx       V.CchAddr,u         point to base of cache
               leax      d,x
               stx       V.CchPSpot,u
* Call low-level driver write routine
writeit        lda       #$01
               sta       V.SectCnt,u
               ldx       V.LLWrite,u
               lbsr      LLCall
* If verify flag is on, read back and compare
               tst       PD.VFY,y            verify flag set?
               bne       ex@                 if so, we don't verify -- just exit
* Read back physical sector into cache
               tst       V.HDBPart,u         HDB-DOS partition?
               beq       o@
* If in HDB-DOS mode, we simply place the base address of the cache into 
* V.CchPSpot... and V.CchLSpot for later verify
               ldx       V.CchAddr,u
               stx       V.CchPSpot,u
               stx       V.CchLSpot,u
o@             lda       #$01
               sta       V.SectCnt,u
               ldx       V.LLRead,u
               lbsr      LLCall
* Now compare PD.BUF to sector in cache just re-read         
               ldx       V.CchLSpot,u        get spot in cache where 256 byte sector is.
               ldy       PD.BUF,y            get pointer to buffer
               clra      
a@             ldb       ,x+                 get byte in cache
               cmpb      ,y+                 compare against byte in PD.BUF
               bne       err@
               deca      
               bne       a@
ex@            clrb      
               rts       
err@           comb      
               ldb       #E$Write
               stb       V.CchDirty,u        make cache dirty due to error
               rts       

*
* Init
*
* Entry:
*    Y  = address of device descriptor
*    U  = address of device memory area
*
* Exit:
*    CC = carry set on error
*    B  = error code
*
Init           pshs      y                   save device descriptor ptr on stack
               ldb       #DrvCount           get maximum drives supported
               stb       V.NDRV,u            save in our device memory
               leax      DRVBEG,u            point X to the drive tables
               lda       #$FF
* Invalidate V.NDRV drive tables
drvx           sta       DD.TOT,x
               sta       DD.TOT+1,x
               sta       DD.TOT+2,x
               leax      DRVMEM,x            point to next drive table
               decb                          decrement counter
               bne       drvx                if not zero, continue
* Link to low-level driver
               ldd       IT.LLDRV,y          point to name in descriptor
               leax      d,y                 point to name in descriptor
               pshs      u
               IFGT      Level-1
               ldd       D.Proc              get curr proc ptr
               pshs      d                   save on stack
               ldd       D.SysPrc            get system process desc ptr
               std       D.Proc              and make current proc
               ENDC      
               lda       #Sbrtn+Objct
               os9       F$Link              link to it
               IFGT      Level-1
               puls      x                   get curr proc ptr
               stx       D.Proc              restore
               ENDC      
               tfr       u,x                 transfer module address to X
               puls      u                   restore U
               leau      UOFFSET,u
               bcs       ret@
               stx       V.LLAddr,u          else save module address
* setup entry points to low-level module
               leax      V.LLInit,u
               lda       #6                  number of entry points
l@             sty       ,x++
               leay      3,y
               deca      
               bne       l@
* Call low-level driver init
               ldy       ,s                  grab path desc ptr
               ldx       V.LLInit,u
               lbsr      LLCall
               bcc       r@
ret@           puls      y,pc
* Allocate cache memory
r@             lda       IT.TYP,y            get type byte
               anda      #TYPH.SSM           mask out all but sector size
* Added Dec 20, 2011: save off to V.SectSize (never got initialized until now!)
               sta       V.SectSize,u        clear out V.SectSize
               puls      y
* Fall through to ExpandCache

* Entry: A = cache size to expand to (1 = 512, 2 = 1024, 3 = 2048)
* Exit:  D is destroyed
* Note: any previously allocated cache memory must have been
* freed before this call!
* 
ExpandCache              
               pshs      a,x
               leax      CCHTBL,pcr
               lda       a,x                 get 1, 2, 4 or 8 
               sta       V.CchDirty,u        make cache dirty since we will expand it
               clrb      
               std       V.CchSize,u         save cache size (256, 512, 1024 or 2048)
               tfr       u,x
               os9       F$SRqMem            allocate cache memory
               stu       V.CchAddr,x         save cache ptr
               tfr       x,u                 restore mem pointer
ex@            puls      a,x,pc


CCHTBL         FCB       256/256
               FCB       512/256
               FCB       1024/256
               FCB       2048/256

MASKTBL        FCB       $07,$06,$04,$00

               EMOD      
eom            EQU       *
               END