 lib environment
 sttl Disk Space Managers
 pag
 name diskman
 global mapfil,getmb,asnib,fndsir,aldb
 global filfr,clrbfr,frdb,mkfch,update
 global rmvfil,publn,frtin,frind

SORT_FREE_LIST set 1

*
* mapfil
*
* Given a file's logical block number, return the
* physical block number.  This is the main block
* mapping algorithm.  On entry, U points to the
* fdn entry, Y.X has the logical block number, and
* 'umaprw' is zero if we are reading the file.
* If the block is not allocated and we are
* reading, return an 'eq' status.  If writing and
* a block is not found, allocate it.
*

mapfil pshs x,y,u save regs
 cmpy #0 check if block > 65K
 bne mapfi8 if != 0, then greater!
 cmpx #9 check for direct block
 bhi mapfi3
 clra -- ldd #0 zero out read ahead block
 clrb
 std unxtbl
 sta unxtbl+2
 tfr x,d get block number
 cmpb #9 is it block 9?
 beq mapfi2 if so, no read ahead
 pshs b multiply block by 3
 aslb which is block size
 addb 0,s
 leay ffmap+3,u point to map entry
 leay b,y
 ldd 0,y get read ahead block
 std unxtbl
 lda 2,y
 sta unxtbl+2
 puls b reset block number
mapfi2 bsr getmb get map block
 bra mapf45 go finish up

 pag

*
* This part of mapfil handles the first indirection
* block.  It will map block numbers between 10 and 137.
*

mapfi3 leax -10,x subtract 10 from block number
 stx 0,s save new block
 cmpx #127 is it in 1st indirect?
 bhi mapfi5
 ldb #10 set map byte
 bsr getmb get map block
 beq mapf45 allocated?
mapfi4 lda 1,s get block offset
 lbsr getib do indirection
mapf45 leas 4,s clean up stack
 puls u,pc return


*
* This part of mapfil handles the two indirect block
* accessing.  This is for blocks 138 through 16,521.
*

mapfi5 leax -128,x subtract 128 from block
 stx 0,s save new block
 cmpx #16383 is it in range?
 bhi mapfi7
 ldb #11 set map byte
 bsr getmb get map block
 beq mapf45 allocated?
mapfi6 ldd 0,s get block
 aslb get bits 7->13
 rola into a
 bsr getib get the indirection block
 bne mapfi4 allocated?
 bra mapf45 finish up


 pag

*
* This part of mapfil handles blocks 16,522 and above.
* Three levels of indirection are performed.
*

mapfi7 leax -16384,x subtract off bias
 stx 0,s save new block
 bra mapfi9
mapfi8 tfr x,d get block
 subd #(10+128+16384)
 std 0,s save new block
 bcc mapfi9 dec top half?
 dec 3,s do overflow
mapfi9 ldb #12 set map byte
 bsr getmb get map block
 beq mapf45 allocated?
 lda 3,s get top 7 bits
 ldb 0,s of 21 bit block addr
 aslb
 rola put them in a
 aslb
 rola
 bsr getib do indirection
 bne mapfi6 allocated?
 bra mapf45 finish up


 pag

*
* getmb
*
* Get the fdn map block designated by b.  There
* are 13 map cells in the fdn, 0 thru 9 are
* direct blocks while 10 thru 12 are indirect.
* Return the block in Y.X or 'eq' if not allocated
* and we are reading.  If writing and block
* needs allocated, do it.  U has the fdn pointer.
*

getmb pshs u,b save data
 leay ffmap,u point to file map
 aslb mul block by 3
 addb 0,s+
 leay b,y point to selected block
 ldb 0,y get hi block
 ldx 1,y get lo block
 bne getmb4 is it null?
 tstb test hi part
 bne getmb4 is it null?
 tst umaprw are we reading?
 beq getmb5 eq if read
 ldd fdevic,u get device number
 pshs y save map ptr
 lbsr aldb allocate disk block
 puls x reset map ptr
 beq getmb5 no blocks left?
 leas -4,s save stack space
 clr 2,s
 ldd bfblck,y get block number (lo)
 std 1,x set in map
 std 0,s save on stack
 lda bfblch,y get hi blk number
 sta 0,x set in map
 sta 3,s save on stack
 lda fstat,u get fdn status
 ora #FMOD set mod flag
 sta fstat,u save new status
 lbsr wbflat write the new buffer
 clz set ret status
 puls x,y,u,pc return
getmb4 clra clear top half hi blk
 tfr d,y put hi blk in y
 clz set ret status
getmb5 puls u,pc return

 pag

*
* getib
*
* Get the indirection block address from the
* block designated by Y.X, and map slot in A.
* U points to the fdn and umaprw is valid.
* Return 'eq' if no map allocated, else return
* the block in Y.X.
*

getib anda #$7f get low 7 bits
 pshs a,x,y,u save all data
 clra -- ldd #0 clear out read ahead block
 clrb
 std unxtbl
 sta unxtbl+2
 ldd fdevic,u get device number
 lbsr rdbuf read in the indirect block
 pshs y save buffer
 ldx 0,s point to buffer
 lbsr mapbpt map buffer into space
 pshs d save offset
 ldb 4,s get map slot
 lda #3 multiply by block size
 mul
 tfr d,y save offset
 addd 0,s add in offset
 std 0,s save total buf offset
 ldx #SBUFFR point to buffer space
 cmpy #(3*127) last map slot?
 beq getib2 if so, no read ahead
 addd #3 get next seq. block
 ldy d,x get block
 sty unxtbl set read ahead
 addd #2
 lda d,x get lo byte of block
 sta unxtbl+2 save the byte
 ldd 0,s reset count
getib2 leax d,x point to requested block
 ldd 1,x get lo block
 std 5,s save on stack (x)
 lda 0,x get hi block
 clr 7,s set on stack (y)
 sta 8,s
 bne getib4 is it null?
 ldd 5,s
 bne getib4
 ldu 9,s reset fdn pointer
 tst umaprw are we reading?
 bne asnib if not, go allocate
getib3 leas 2,s rip off stack
 puls y get buffer ptr
 lbsr freebf free the buffer
 sez set ret status
 puls a,x,y,u,pc return
getib4 leas 2,s fix stack
 puls y get buffer ptr
 lbsr freebf free buffer
 clz set ret status
 puls a,x,y,u,pc return

 pag

*
* asnib
*
* Assign a new indirect block to the file.  This
* routine is only entered from getib and may not
* be called otherwise.
*

asnib ldd fdevic,u get device number
 bsr aldb allocate a disk block
 beq getib3 no space left?
 pshs y save buffer
 ldx 4,s get orig block
 lbsr mapbuf map in buffer
 puls y get buffer ptr
 puls d get buffer offset
 ldx #SBUFFR point to buffer space
 leax d,x point to map cell
 ldd bfblck,y get block number
 std 1,x save in i.block
 std 3,s save new block
 lda bfblch,y get hi block num
 sta 0,x put in buffer
 sta 6,s save it
 lbsr wbflat write out buffer
 puls y get buffer ptr
 lbsr wbflat write it out
 clz set status
 puls a,x,y,u,pc return

*
* fndsir
*
* Find the sir associated with device in D.
* Return with sir pointed at by X.
*

fndsir ldy mtable point to mount table
fndsi1 cmpd mdevic,y compare device number
 bne fndsi2
 ldx msir,y get sir pointer
 rts return
fndsi2 leay MSTSIZ,y goto next entry
 bra fndsi1

 pag

*
* aldb
*
* Allocate a disk block from the device specified
* in D.  U is pointing to the fdn and should be
* preserved.  Exit 'eq' if no space left, else return
* block in buffer pointed at by header in Y.
*

aldb pshs u,d save data
 bsr fndsir find the sir
 lbeq aldb7 no sir?
aldb2 lda slkfr,x get free lock
 beq aldb3 is sir locked?
 pshs x save sir ptr
 ldy 0,s point to sir
 leay slkfr,y point to lock
 ldb #FDNPR set priority
 lbsr sleep go sleep
 puls x get sir ptr
 bra aldb2 repeat loop
aldb3 ldb snfree,x get free count
 lbeq aldb7 none left?
 decb dec the count
 stb snfree,x save new count
 leay sfree,x point to free list
 lda #3 mul offset by 3 (block size)
 mul
 leay d,y point to selected entry
 ldb 0,y get hi block
 clra
 pshs d save hi block number
 ldd 1,y get lo block number
 pshs d save it
 bne aldb4 is it zero?
 tst 3,s is hi null?
 beq aldb6
aldb4 tst snfree,x check if free to zero
 bne aldb5

 pag

*
* filfr
*
* Fill free list.  Only entered from above!
*

filfr inc slkfr,x set free list lock
 pshs x save sir ptr
 ldx 2,s get block number
 ldy 4,s
 ldd 6,s get device number
 lbsr rdbuf read in buffer
 tfr y,x save buffer ptr
 ldy 0,s get sir ptr
 lda #100 set count back to 100
 sta snfree,y
 ldu #0 set offset to 0
 ldd #(3*100) set byte count
 leay sfree,y point to free list
 pshs x save buffer ptr
 lbsr cpybts copy buffer contents
 puls y get buffer
 lbsr freebf free it up
 ldy 0,s get sir ptr
 leay slkfr,y point to lock
 clr 0,y unlock free list
 lbsr wakeup wakeup those sleeping
 puls x get sir ptr


 pag

*
* aldb ... continued
*
* This routine is split for readability?
*

aldb5 ldd sfreec+1,x get total count
 subd #1 dec by one
 std sfreec+1,x save new value
 bcc aldb55 overflow?
 dec sfreec,x dec total free count
aldb55 pshs x save sir ptr
 ldx 2,s get block number
 ldy 4,s
 ldd 6,s get device number
* jsr chkblk * test code *
 lbsr alocbf allocate the buffer
 puls x point to sir
 lda #1 set update flag
 sta supdt,x
 bsr clrbfr clear the buffer
 leas 4,s clean up stack
 clz set return status
 puls u,d,pc return
aldb6 leas 4,s clean up stack
aldb7 sez set ret status
 puls u,d,pc return


*
* clrbfr
*
* Clear the buffer headed by Y.
*

clrbfr pshs y save buffer
 tfr y,x
 lbsr mapbpt map in buffer
 leay 512,x set end point
 pshs y save it
 clra -- ldd #0 set null word
 clrb
clrbf2 std 0,x++ clear word
 cmpx 0,s end of buffer?
 bne clrbf2
 leas 2,s clean stack
 puls y,pc return

 pag

*
* frdb
*
* Free the disk block contained in Y.X and on
* the device represented by D.  The block is
* added to the list in the sir, and if the list
* exceeds 100 items, it is written out to disk.
*

frdb pshs d,x,y save data
* jsr chkblk * test code *
 lbsr fndsir find the sir
 beq frdb8 null sir?
frdb2 lda slkfr,x check free lock
 beq frdb3 is free list locked?
 pshs x save sir
 leay slkfr,x point to lock
 ldb #FDNPR set priority
 lbsr sleep goto sleep
 puls x reset sir
 bra frdb2 repeat
frdb3 lda snfree,x get free count
 bne frdb4 is it 0?
 clra -- ldd #0 if so, zero first block
 clrb
 sta sfree,x of free list
 std sfree+1,x
 inc snfree,x bump free count
 bra frdb5
frdb4 cmpa #100 list full?
 bne frdb5
 bsr mkfch make a new free chain block
frdb5 lda #1 set update flag
 sta supdt,x
 ldb snfree,x get free index
 lda #3 multiply by block size
 mul
 leay sfree,x point to free list
 leay d,y point to entry
 ldd 2,s get block number
 std 1,y save in list
 lda 5,s get hi part of block
 sta 0,y save in list
 inc snfree,x bump count
 ldd stafre+1 get freed count
 addd #1 bump by 1
 std stafre+1
 bcc frdb7
 inc stafre bump hi part
frdb7 ldd sfreec+1,x get total count
 addd #1 bump by one
 std sfreec+1,x save new value
 bcc frdb8 overflow?
 inc sfreec,x bump total free count
frdb8 puls d,x,y,pc return


 pag

*
* mkfch
*
* Make a new free chain block by copying the current
* sir free list into a block and writing it out
* to the disk.
*

mkfch inc slkfr,x set free lock
 pshs x save sir
 ldd 4,s get device number
 ldx 6,s get block number
 ldy 8,s
 lbsr alocbf alocate a buffer
 pshs y save buffer ptr
 lda bfflag,y get flags
 anda #!BFLAT clear later bit ************* 1-9-81 *****
 sta bfflag,y save new flags
 ldx 0,s point to buffer
 ldd #(3*100) set byte count
 ldu #0 set offset
 ldy 2,s point to sir
 leay sfree,y point to free list
 if SORT_FREE_LIST
* -- Sort free block list 4/2/84
 pshs d,x,y,u save registers
 leau 100*3,y end of list
 leax 3,y
10 leay 3,x
 pshs u
 cmpy ,s++
 beq 40f
20 ldd 0,x
 cmpd 0,y
 bhi 30f jump if in order
 blo 25f jump if swap needed
 lda 2,x
 cmpa 2,y
 bhi 30f jump if no swap needed
25 ldd 0,x swap elements
 pshs d
 lda 2,x
 pshs a
 ldd 0,y
 std 0,x
 lda 2,y
 sta 2,x
 puls a
 sta 2,y
 puls d
 std 0,y
30 leay 3,y
 pshs u
 cmpy ,s++
 bne 20b
 leax 3,x
 pshs u
 cmpx ,s++
 bne 10b
40 puls d,x,y,u restore registers
* --
 endif
 lbsr cpystb copy data to buffer
 puls y get buffer
 lbsr wrbuf write out the buffer
 ldy 0,s get sir
 clr snfree,y set free count to 0
 leay slkfr,y point to free lock
 clr 0,y unlock free list
 lbsr wakeup wakeup those sleeping
 puls x,pc return


 pag

*
* update
*
* Update all disk information.  The fdn table is
* searched for fdn's which need written out, as
* well as the sir's are checked for updating.
* All disk buffers marked for 'write later' are
* forced out to disk also.
*

update tst updlck check if update in progress?
 beq updat1 if so, just exit
 rts return
updat1 inc updlck lock out others
 ldx #fdnbsy point to list of busy fdns
updat2 ldx ffwdl,x follow fwd link
 beq updat4 end of list?
 lda fstat,x get fdn status
 bita #FLOCK is it locked?
 bne updat2
 bita #FMOD has it been modified?
 beq updat2 if not, no write!
 ora #FLOCK lock this fdn
 sta fstat,x
 inc frefct,x bump the reference cnt
 lbsr updfdn update this fdn
 lbsr frefdn free the fdn
 bra updat2 repeat for rest


 pag

*
* update continued ...
*

updat4 ldy mtable point to mount table
 ldb smnt get total mount count
updat5 ldx msir,y get sir
 beq updat7 no mount here?
 cmpx #$aaaa is it temp value?
 beq updat7
 pshs y,b save info
 lda slkfr,x check if being used
 ora slkfdn,x
 ora swprot,x or write protected
 bne updat6 if so, no update
 lda supdt,x has it been modified?
 beq updat6 if not, skip
 pshs x save sir
 clr supdt,x clear out mod flag
 ldd mdevic,y get device number of sir
 ldx #1 set block number to 1
 ldy #0 (fdn number of sir)
 lbsr alocbf allocate a buffer
 tfr y,x save buffer pointer
 puls y get sir pointer
 pshs x save buffer
 ldd stiml get system time
 std sutime+2,y save in sir
 ldd stimh get hi part
 std sutime,y save it
 ldu #0 set offset of 0
 ldd #512 set byte count (buffer)
 lbsr cpystb copy sir to buffer
 puls y get buffer
 lbsr wrbuf write out the sir
updat6 puls y,b reset mount data
updat7 leay MSTSIZ,y move to next mount
 decb dec the count
 bne updat5 repeat?
 clr updlck unlock update
 lbra flsha flush all disk buffers


 pag

*
* rmvfil
*
* Remove all disk blocks associated with the
* fdn pointed at by x.
*

rmvfil pshs x save fdn
 lda fmode,x get fdn mode
 bita #(FSCHR|FSBLK) is it device?
 beq rmvfi2
 puls x,pc return if device
rmvfi2 clra -- ldd #0 clear out file size
 clrb
 std fsize,x
 std fsize+2,x
 ldd fdevic,x get device number
 leax ffmap+(12*3),x point to last map entry
 bsr publn pickup block number
 beq rmvfi4 is it null?
 bsr frtin free triple ind. blocks
rmvfi4 ldx 0,s point to fdn
 ldd fdevic,x get device number
 leax ffmap+(11*3),x point to 12th map entry
 bsr publn get block number
 beq rmvfi5 is it null?
 bsr frdin free double ind. blocks
rmvfi5 ldx 0,s point to fdn
 ldd fdevic,x get device number
 leax ffmap+(10*3),x point to 11th entry
 bsr publn get block number
 beq rmvfi6 is it null?
 bsr frsin free single ind. blocks
rmvfi6 ldx 0,s get fdn pointer
 ldd fdevic,x get device number
 pshs d save it
 ldb #9 set counter
 pshs b save it
rmvfi7 ldb 0,s get index
 lda #3 set block size
 mul calc total offset
 ldx 3,s point to fdn
 leax ffmap,x point to file map
 leax b,x point to this entry
 ldd 1,s get device number
 bsr publn get block number
 beq rmvfi8 is it null?
 lbsr frdb free the block
rmvfi8 dec 0,s dec the index counter
 bpl rmvfi7 repeat?
 leas 3,s fix stack
 ldx 0,s point to fdn
 leax ffmap,x point to file map
 ldb #13*3 set map size count
rmvfi9 clr 0,x+ clear out file map
 decb dec the counter
 bne rmvfi9 finished?
 puls x reset fdn ptr
 lda fstat,x get fdn status
 ora #FMOD set mod bit
 sta fstat,x save new status
 rts return

 pag

*
* publn
*
* Pickup the disk block number pointed at by
* x.  If the block is null, return 'eq' status.
* Else return the block in Y.X.
*

publn pshs d save device number
 ldb 0,x get hi part
 clra
 tfr d,y put hi part in y
 ldx 1,x get lo part
 bne publn2 is it null?
 cmpy #0 is hi part null?
publn2 puls d,pc return

*
* frtin, frdin, frsin
*
* Free the blocks associated with the triple
* double, and single indirect blocks.  On entry
* the block number is in Y.X and D has the
* device number.  Transfer the freeing routines
* name in U to frind who actually frees the blocks.
*

frtin ldu #frdin set up free routine
 bra frind

frdin ldu #frsin set up free routine
 bra frind

frsin ldu #frdb set up free routine

* fall thru to frind


 pag

*
* frind
*
* Free all disk blocks in the indirect block whose
* number is in Y.X and device D.  U contains a
* pointer to the routine which should be called
* to do the actual block freeing.
*

frind pshs d,x,y,u save all args
 lbsr rdbuf read in the ind block
 pshs y save buffer header
 ldd #127*3 set up index
frind2 pshs d save index
 ldx 2,s point to buffer hdr
 lbsr mapbpt map in the buffer
 ldd 0,s reset the index
 leax d,x point to entry
 ldb 0,x get hi block number
 clra
 pshs d save hi part
 ldx 1,x get lo part of block
 puls y reset hi part
 bne frind3 is it null?
 cmpy #0
 beq frind4
frind3 ldd 4,s get device number
 jsr [10,s] call free routine
frind4 puls d reset map ptr data
 subd #3 dec index one block
 bpl frind2 repeat?
 puls y get buffer header
 lbsr freebf free the buffer
 puls d,x,y,u get all args
 lbra frdb free the ind block & exit


* test code *
*
*chkblk cmpd #4
* bne chkbl1
* cmpy #0
* bne chkbl2
* cmpx #402
* blo chkbl2
*chkbl1 rts
*chkbl2 sts $f0
* stx $f2
* sty $f4
* lda $e
* sta $f6
* lda #$01
* sta $fffb
* ldx #chkblm
* jmp blowup
*chkblm fcc "Don't Touch! Call Dave",0
*
