; ;********************************************************************** ;***************************************************************** ; ; Error Messages if BANKED md equ 0 else md equ 24h endif dskmsg: db 'CP/M Error On ' dskerr: db ' : ',md permsg: db 'Disk I/O',md selmsg: db 'Invalid Drive',md rofmsg: db 'Read/Only File',md rodmsg: db 'Read/Only Disk',md if not MPM passmsg: if BANKED db 'Password Error',md endif fxstsmsg: db 'File Exists',md wildmsg: db '? in Filename',md endif if MPM setlret1: mvi a,1 sta$ret: sta aret func$ret: ret entsp: ds 2 endif ;***************************************************************** ;***************************************************************** ; ; common values shared between bdosi and bdos if MPM usrcode:db 0 ; current user number endif aret: ds 2 ; address value to return lret equ aret ; low(aret) ;***************************************************************** ;***************************************************************** ;** ** ;** b a s i c d i s k o p e r a t i n g s y s t e m ** ;** ** ;***************************************************************** ;***************************************************************** ; literal constants true equ 0ffh ; constant true false equ 000h ; constant false enddir equ 0ffffh ; end of directory byte equ 1 ; number of bytes for "byte" type word equ 2 ; number of bytes for "word" type ; fixed addresses in low memory tfcb equ 005ch ; default fcb location tbuff equ 0080h ; default buffer location ; error message handlers rod$error: ; report read/only disk error mvi c,2! jmp goerr rof$error: ; report read/only file error mvi c,3! jmp goerr sel$error: ; report select error mvi c,4 ; Invalidate curdsk to force select call ; at next curselect call mvi a,0ffh! sta curdsk goerr: ; hl = .errorhandler, call subroutine mov h,c! mvi l,0ffh! shld aret if MPM call test$error$mode! jnz rtn$phy$errs mov a,c! lxi h,pererr-2! jmp bdos$jmp else goerr1: lda adrive! sta errdrv lda error$mode! inr a! cnz error endif rtn$phy$errs: if MPM lda lock$shell! ora a! jnz lock$perr endif ; Return 0ffffh if fx = 27 or 31 lda fx cpi 27! jz goback0 cpi 31! jz goback0 jmp goback if MPM test$error$mode: lxi d,pname+4 test$error$mode1: call rlr! dad d mov a,m! ani 80h! ret endif if BANKED set$copy$cr$only: lda copy$cr$init! sta copy$cr$only! ret reset$copy$cr$only: xra a! sta copy$cr$init! sta copy$cr$only! ret endif bde$e$bde$m$hl: mov a,e! sub l! mov e,a mov a,d! sbb h! mov d,a rnc! dcr b! ret bde$e$bde$p$hl: mov a,e! add l! mov e,a mov a,d! adc h! mov d,a rnc! inr b! ret shl3bv: inr c shl3bv1: dcr c! rz dad h! adc a! jmp shl3bv1 incr$rr: call get$rra inr m! rnz inx h! inr m! rnz inx h! inr m! ret save$rr: call save$rr2! xchg save$rr1: mvi c,3! jmp move ; ret save$rr2: call get$rra! lxi d,save$ranr! ret reset$rr: call save$rr2! jmp save$rr1 ; ret compare: ldax d! cmp m! rnz inx h! inx d! dcr c! rz jmp compare ; ; local subroutines for bios interface ; move: ; Move data length of length c from source de to ; destination given by hl inr c ; in case it is zero move0: dcr c! rz ; more to move ldax d! mov m,a ; one byte moved inx d! inx h ; to next byte jmp move0 selectdisk: ; Select the disk drive given by register D, and fill ; the base addresses curtrka - alloca, then fill ; the values of the disk parameter block mov c,d ; current disk# to c ; lsb of e = 0 if not yet logged - in call seldskf ; hl filled by call ; hl = 0000 if error, otherwise disk headers mov a,h! ora l! rz ; Return with C flag reset if select error ; Disk header block address in hl mov e,m! inx h! mov d,m! inx h ; de=.tran shld cdrmaxa! inx h! inx h ; .cdrmax shld curtrka! inx h! inx h ; hl=.currec shld curreca! inx h! inx h ; hl=.buffa inx h! shld drvlbla! inx h shld lsn$add! inx h! inx h ; de still contains .tran xchg! shld tranv ; .tran vector lxi h,dpbaddr ; de= source for move, hl=dest mvi c,addlist! call move ; addlist filled ; Now fill the disk parameter block lhld dpbaddr! xchg ; de is source lxi h,sectpt ; hl is destination mvi c,dpblist! call move ; data filled ; Now set single/double map mode lhld maxall ; largest allocation number mov a,h ; 00 indicates < 255 lxi h,single! mvi m,true ; Assume a=00 ora a! jz retselect ; high order of maxall not zero, use double dm mvi m,false retselect: ; C flag set indicates successful select stc! ret home: ; Move to home position, then offset to start of dir call homef xra a ; constant zero to accumulator lhld curtrka! mov m,a! inx h! mov m,a ; curtrk=0000 lhld curreca! mov m,a! inx h! mov m,a ; currec=0000 inx h! mov m,a ; currec high byte=00 if MPM lxi h,0! shld dblk ; dblk = 0000 endif ret rdbuff: ; Read buffer and check condition mvi a,1! sta readf$sw call readf ; current drive, track, sector, dma jmp diocomp ; Check for i/o errors wrbuff: ; Write buffer and check condition ; write type (wrtype) is in register c xra a! sta readf$sw call writef ; current drive, track, sector, dma diocomp: ; Check for disk errors ora a! rz mov c,a call chk$media$flag mov a,c cpi 3! jc goerr mvi c,1! jmp goerr chk$media$flag: ; A = 0ffh -> media changed inr a! rnz if BANKED ; Handle media changes as I/O errors for ; permanent drives call chksiz$eq$8000h! rz endif ; BIOS says media change occurred ; Is disk logged-in? lhld dlog! call test$vector! mvi c,1! rz ; no - return error call media$change pop h ; Discard return address ; Was this a flush operation (fx = 48)? lda fx! cpi 48! rz ; yes ; Is this a flush to another drive? lxi h,adrive! lda seldsk! cmp m! jnz reset$relog ; Bail out if fx = read, write, close, or search next call chk$exit$fxs ; Is this a directory read operation? lda readf$sw! ora a! rnz ; yes ; Error - directory write operation mvi c,2! jmp goerr ; Return disk read/only error reset$relog: ; Reset relog if flushing to another drive xra a! sta relog! ret if BANKED chksiz$eq$8000h: ; Return with Z flag set if drive permanent ; with no checksum vector lhld chksiz! mvi a,80h! cmp h! rnz xra a! cmp l! ret endif seekdir: ; Seek the record containing the current dir entry if MPM lxi d,0ffffh ; mask = ffff lhld dblk! mov a,h! ora l! jz seekdir1 lda blkmsk! mov e,a! xra a! mov d,a ; mask = blkmsk lda blkshf! mov c,a! xra a call shl3bv ; ahl = shl(dblk,blkshf) seekdir1: push h! push a ; Save ahl endif lhld dcnt ; directory counter to hl mvi c,dskshf! call hlrotr ; value to hl shld drec if MPM ; arecord = shl(dblk,blkshf) + shr(dcnt,dskshf) & mask mov a,l! ana e! mov l,a ; dcnt = dcnt & mask mov a,h! ana d! mov h,a pop b! pop d! call bde$e$bde$p$hl else mvi b,0! xchg endif set$arecord: lxi h,arecord mov m,e! inx h! mov m,d! inx h! mov m,b ret seek: ; Seek the track given by arecord (actual record) lhld curtrka! mov c,m! inx h! mov b,m ; bc = curtrk push b ; s0 = curtrk lhld curreca! mov e,m! inx h! mov d,m inx h! mov b,m ; bde = currec lhld arecord! lda arecord+2! mov c,a ; chl = arecord seek0: mov a,l! sub e! mov a,h! sbb d! mov a,c! sbb b push h ; Save low(arecord) jnc seek1 ; if arecord >= currec then go to seek1 lhld sectpt! call bde$e$bde$m$hl ; currec = currec - sectpt pop h! xthl! dcx h! xthl ; curtrk = curtrk - 1 jmp seek0 seek1: lhld sectpt! call bde$e$bde$p$hl ; currec = currec + sectpt pop h ; Restore low(arecord) mov a,l! sub e! mov a,h! sbb d! mov a,c! sbb b jc seek2 ; if arecord < currec then go to seek2 xthl! inx h! xthl ; curtrk = curtrk + 1 push h ; save low (arecord) jmp seek1 seek2: xthl! push h ; hl,s0 = curtrk, s1 = low(arecord) lhld sectpt! call bde$e$bde$m$hl ; currec = currec - sectpt pop h! push d! push b! push h ; hl,s0 = curtrk, ; s1 = high(arecord,currec), s2 = low(currec), ; s3 = low(arecord) xchg! lhld offset! dad d mov b,h! mov c,l! shld track call settrkf ; call bios settrk routine ; Store curtrk pop d! lhld curtrka! mov m,e! inx h! mov m,d ; Store currec pop b! pop d! lhld curreca! mov m,e! inx h! mov m,d inx h! mov m,b ; currec = bde pop b ; bc = low(arecord), de = low(currec) mov a,c! sub e! mov l,a ; hl = bc - de mov a,b! sbb d! mov h,a call shr$physhf mov b,h! mov c,l lhld tranv! xchg ; bc=sector#, de=.tran call sectran ; hl = tran(sector) mov c,l! mov b,h ; bc = tran(sector) shld sector call setsecf ; sector selected lhld curdma! mov c,l! mov b,h! jmp setdmaf ; ret shr$physhf: lda physhf! mov c,a! jmp hlrotr ; file control block (fcb) constants empty equ 0e5h ; empty directory entry lstrec equ 127 ; last record# on extent recsiz equ 128 ; record size fcblen equ 32 ; file control block size dirrec equ recsiz/fcblen ; directory fcbs / record dskshf equ 2 ; log2(dirrec) dskmsk equ dirrec-1 fcbshf equ 5 ; log2(fcblen) extnum equ 12 ; extent number field maxext equ 31 ; largest extent number ubytes equ 13 ; unfilled bytes field modnum equ 14 ; data module number maxmod equ 64 ; largest module number fwfmsk equ 80h ; file write flag is high order modnum namlen equ 15 ; name length reccnt equ 15 ; record count field dskmap equ 16 ; disk map field lstfcb equ fcblen-1 nxtrec equ fcblen ranrec equ nxtrec+1; random record field (2 bytes) ; reserved file indicators rofile equ 9 ; high order of first type char invis equ 10 ; invisible file in dir command ; utility functions for file access dm$position: ; Compute disk map position for vrecord to hl lxi h,blkshf! mov c,m ; shift count to c lda vrecord ; current virtual record to a dmpos0: ora a! rar! dcr c! jnz dmpos0 ; a = shr(vrecord,blkshf) = vrecord/2**(sect/block) mov b,a ; Save it for later addition mvi a,8! sub m ; 8-blkshf to accumulator mov c,a ; extent shift count in register c lda extval ; extent value ani extmsk dmpos1: ; blkshf = 3,4,5,6,7, c=5,4,3,2,1 ; shift is 4,3,2,1,0 dcr c! jz dmpos2 ora a! ral! jmp dmpos1 dmpos2: ; Arrive here with a = shl(ext and extmsk,7-blkshf) add b ; Add the previous shr(vrecord,blkshf) value ; a is one of the following values, depending upon alloc ; bks blkshf ; 1k 3 v/8 + extval * 16 ; 2k 4 v/16+ extval * 8 ; 4k 5 v/32+ extval * 4 ; 8k 6 v/64+ extval * 2 ; 16k 7 v/128+extval * 1 ret ; with dm$position in a getdma: lhld info! lxi d,dskmap! dad d! ret getdm: ; Return disk map value from position given by bc call getdma dad b ; Index by a single byte value lda single ; single byte/map entry? ora a! jz getdmd ; Get disk map single byte mov l,m! mov h,b! ret ; with hl=00bb getdmd: dad b ; hl=.fcb(dm+i*2) ; double precision value returned mov a,m! inx h! mov h,m! mov l,a! ret index: ; Compute disk block number from current fcb call dm$position ; 0...15 in register a sta dminx mov c,a! mvi b,0! call getdm ; value to hl shld arecord! mov a,l! ora h! ret atran: ; Compute actual record address, assuming index called ; arecord = shl(arecord,blkshf) lda blkshf! mov c,a lhld arecord! xra a! call shl3bv shld arecord! sta arecord+2 shld arecord1 ; Save low(arecord) ; arecord = arecord or (vrecord and blkmsk) lda blkmsk! mov c,a! lda vrecord! ana c mov b,a ; Save vrecord & blkmsk in reg b & blk$off sta blk$off lxi h,arecord! ora m! mov m,a! ret get$atts: ; Get volatile attributes starting at f'5 ; info locates fcb lhld info lxi d,8! dad d ; hl = .fcb(f'8) mvi c,4 get$atts$loop: mov a,m! add a! push a mov a,d! rar! mov d,a pop a! rrc! mov m,a dcx h! dcr c! jnz get$atts$loop mov a,d! ret get$s1: ; Get current s1 field to a call getexta! inx h! mov a,m! ret get$rra: ; Get current ran rec field address to hl lhld info! lxi d,ranrec! dad d ; hl=.fcb(ranrec) ret getexta: ; Get current extent field address to hl lhld info! lxi d,extnum! dad d ; hl=.fcb(extnum) ret getrcnta: ; Get reccnt address to hl lhld info! lxi d,reccnt! dad d! ret getfcba: ; Compute reccnt and nxtrec addresses for get/setfcb call getrcnta! xchg ; de=.fcb(reccnt) lxi h,(nxtrec-reccnt)! dad d ; hl=.fcb(nxtrec) ret getfcb: ; Set variables from currently addressed fcb call getfcba ; addresses in de, hl mov a,m! sta vrecord ; vrecord=fcb(nxtrec) xchg! mov a,m! ora a! jnz getfcb0 call get$dir$ext! mov c,a! call set$rc! mov a,m getfcb0: cpi 81h! jc getfcb1 mvi a,80h getfcb1: sta rcount ; rcount=fcb(reccnt) or 80h call getexta ; hl=.fcb(extnum) lda extmsk ; extent mask to a ana m ; fcb(extnum) and extmsk sta extval ret setfcb: ; Place values back into current fcb call getfcba ; addresses to de, hl ; fcb(cr) = vrecord lda vrecord! mov m,a ; Is fx < 22? (sequential read or write) lda fx! cpi 22! jnc $+4 ; no ; fcb(cr) = fcb(cr) + 1 inr m xchg! mov a,m! cpi 80h! rnc ; dont reset fcb(rc) if > 7fh lda rcount! mov m,a ; fcb(reccnt)=rcount ret zero$ext$mod: call getexta! mov m,d! inx h! inx h! mov m,d ret zero: mov m,b! inx h! dcr c! rz jmp zero hlrotr: ; hl rotate right by amount c inr c ; in case zero hlrotr0: dcr c! rz ; return when zero mov a,h! ora a! rar! mov h,a ; high byte mov a,l! rar! mov l,a ; low byte jmp hlrotr0 compute$cs: ; Compute checksum for current directory buffer lhld buffa ; current directory buffer lxi b,4 ; b = 0, c = 4 compute$cs0: mvi d,32 ; size of fcb xra a ; clear checksum value compute$cs1: add m! inx h! dcr d jnz compute$cs1 xra b! mov b,a! dcr c jnz compute$cs0 ret ; with checksum in a if MPM compute$cs: ; Compute checksum for current directory buffer mvi c,recsiz ; size of directory buffer lhld buffa ; current directory buffer xra a ; Clear checksum value computecs0: add m! inx h! dcr c ; cs = cs+buff(recsiz-c) jnz computecs0 ret ; with checksum in a chksum$fcb: ; Compute checksum for fcb ; Add 1st 12 bytes of fcb + curdsk + ; high$ext + xfcb$read$only + bbh lxi h,pdcnt! mov a,m inx h! add m ; Add high$ext inx h! add m ; Add xfcb$read$only inx h! add m ; Add curdsk adi 0bbh ; Add 0bbh to bias checksum lhld info! mvi c,12! call computecs0 ; Skip extnum inx h ; Add fcb(s1) add m! inx h ; Skip modnum inx h ; Skip fcb(reccnt) ; Add disk map inx h! mvi c,16! call computecs0 ora a! ret ; Z flag set if checksum valid set$chksum$fcb: call chksum$fcb! rz mov b,a! call gets1 cma! add b! cma mov m,a! ret reset$chksum$fcb: xra a! sta comp$fcb$cks call chksum$fcb! rnz call get$s1! inr m! ret endif check$fcb: if MPM xra a! sta check$fcb4 check$fcb1: call chek$fcb! rz check$fcb2: ani 0fh! jnz check$fcb3 lda pdcnt! ora a! jz check$fcb3 call set$sdcnt! sta dont$close call close1 lxi h,lret! inr m! jz check$fcb3 mvi m,0! call pack$sdcnt! mvi b,5 call search$olist! rz check$fcb3: pop h ; Discard return address check$fcb4: nop mvi a,10! jmp sta$ret set$fcb$cks$flag: mvi a,0ffh! sta comp$fcb$cks! ret else call gets1! lhld lsn$add cmp m! cnz chk$media$fcb endif chek$fcb: lda high$ext if MPM ; if ext & 0110$0000b = 0110$0000b then ; set fcb(0) to 0 (user 0) cpi 0110$0000b! jnz chek$fcb1 else ora a! rz endif lhld info! xra a! mov m,a ; fcb(0) = 0 chek$fcb1: if MPM jmp chksum$fcb ; ret else ret chk$media$fcb: ; fcb(s1) ~= DPH login sequence # field ; Is fcb addr < bdosadd? if banked lhld user$info else lhld info endif xchg! lhld bdosadd! call subdh! jnc chk$media1 ; no ; Is rlog(drive) true? lhld rlog! call testvector! rz ; no chk$media1: ; Return invalid fcb error code pop h! pop h chk$media2: mvi a,10! jmp sta$ret endif hlrotl: ; Rotate the mask in hl by amount in c inr c ; may be zero hlrotl0: dcr c! rz ; return if zero dad h! jmp hlrotl0 set$dlog: lxi d,dlog set$cdisk: ; Set a "1" value in curdsk position of bc lda curdsk set$cdisk1: mov c,a ; Ready parameter for shift lxi h,1 ; number to shift call hlrotl ; hl = mask to integrate ldax d! ora l! stax d! inx d ldax d! ora h! stax d! ret nowrite: ; Return true if dir checksum difference occurred lhld rodsk test$vector: lda curdsk test$vector1: mov c,a! call hlrotr mov a,l! ani 1b! ret ; non zero if curdsk bit on check$rodir: ; Check current directory element for read/only status call getdptra ; address of element check$rofile: ; Check current buff(dptr) or fcb(0) for r/o status call ro$test rnc ; Return if not set jmp rof$error ; Exit to read only disk message ro$test: lxi d,rofile! dad d mov a,m! ral! ret ; carry set if r/o check$write: ; Check for write protected disk call nowrite! rz ; ok to write if not rodsk jmp rod$error ; read only disk error getdptra: ; Compute the address of a directory element at ; positon dptr in the buffer lhld buffa! lda dptr addh: ; hl = hl + a add l! mov l,a! rnc ; overflow to h inr h! ret getmodnum: ; Compute the address of the module number ; bring module number to accumulator ; (high order bit is fwf (file write flag) lhld info! lxi d,modnum! dad d ; hl=.fcb(modnum) mov a,m! ret ; a=fcb(modnum) clrmodnum: ; Clear the module number field for user open/make call getmodnum! mvi m,0 ; fcb(modnum)=0 ret clr$ext: ; fcb ext = fcb ext & 1fh call getexta! mov a,m! ani 0001$1111b! mov m,a! ret setfwf: call getmodnum ; hl=.fcb(modnum), a=fcb(modnum) ; Set fwf (file write flag) to "1" ori fwfmsk! mov m,a ; fcb(modnum)=fcb(modnum) or 80h ; also returns non zero in accumulator ret compcdr: ; Return cy if cdrmax > dcnt lhld dcnt! xchg ; de = directory counter lhld cdrmaxa ; hl=.cdrmax mov a,e! sub m ; low(dcnt) - low(cdrmax) inx h ; hl = .cdrmax+1 mov a,d! sbb m ; hig(dcnt) - hig(cdrmax) ; condition dcnt - cdrmax produces cy if cdrmax>dcnt ret setcdr: ; if not (cdrmax > dcnt) then cdrmax = dcnt+1 call compcdr rc ; Return if cdrmax > dcnt ; otherwise, hl = .cdrmax+1, de = dcnt inx d! mov m,d! dcx h! mov m,e ret subdh: ; Compute hl = de - hl mov a,e! sub l! mov l,a! mov a,d! sbb h! mov h,a ret newchecksum: mvi c,0feh ; Drop through to compute new checksum checksum: ; Compute current checksum record and update the ; directory element if c=true, or check for = if not ; drec < chksiz? lhld drec! xchg! lhld chksiz mov a,h! ani 7fh! mov h,a ; Mask off permanent drive bit call subdh ; de-hl rnc ; Skip checksum if past checksum vector size ; drec < chksiz, so continue push b ; Save init flag call compute$cs ; Check sum value to a lhld checka ; address of check sum vector xchg lhld drec dad d ; hl = .check(drec) pop b ; Recall true=0ffh or false=00 to c inr c ; 0ffh produces zero flag jz initial$cs inr c ; 0feh produces zero flag jz update$cs if MPM inr c! jz test$dir$cs endif ; not initializing, compare cmp m ; compute$cs=check(drec)? rz ; no message if ok ; checksum error, are we beyond ; the end of the disk? call nowrite! rnz media$change: call discard$data if MPM call flush$file0 else mvi a,0ffh! sta relog! sta hashl call set$rlog endif ; Reset the drive call set$dlog! jmp reset37x if MPM test$dir$cs: cmp m! jnz flush$files ret endif initial$cs: ; initializing the checksum cmp m! mov m,a! rz ; or 1 into login seq # if media change lhld lsn$add! mvi a,1! ora m! mov m,a! ret update$cs: ; updating the checksum mov m,a! ret set$ro: ; Set current disk to read/only lda seldsk! lxi d,rodsk! call set$cdisk1 ; sets bit to 1 ; high water mark in directory goes to max lhld dirmax! inx h! xchg ; de = directory max lhld cdrmaxa ; hl = .cdrmax mov m,e! inx h! mov m,d ; cdrmax = dirmax ret set$rlog: ; rlog(seldsk) = true lhld olog! call test$vector! rz lxi d,rlog! jmp set$cdisk tst$log$fxs: lda chksiz+1! ani 80h! rnz lxi h,log$fxs tst$log0: lda fx! mov b,a tst$log1: mov a,m! cmp b! rz inx h! ora a! jnz tst$log1 inr a! ret test$media$flag: lhld lsn$add! inx h! mov a,m! ora a! ret chk$exit$fxs: lxi h,goback! push h ; does fx = read or write function? ; and is drive removable? lxi h,rw$fxs! call tst$log0! jz chk$media2 ; yes ; is fx = close or searchn function? ; and is drive removable? lxi h,sc$fxs! call tst$log0! jz lret$eq$ff ; yes pop h! ret tst$relog: lxi h,relog! mov a,m! ora a! rz mvi m,0 drv$relog: call curselect lxi h,0! shld dcnt! xra a! sta dptr ret set$lsn: lhld lsn$add! mov c,m call gets1! mov m,c! ret discard$data$bcb: lhld dtabcba! mvi c,4! jmp discard0 discard$data: lhld dtabcba! jmp discard discard$dir: lhld dirbcba discard: mvi c,1 discard0: mov a,l! ana h! inr a! rz if BANKED mov e,m! inx h! mov d,m! xchg discard1: push h! push b lxi d,adrive! call compare pop b! pop h! jnz discard2 mvi m,0ffh discard2: lxi d,13! dad d mov e,m! inx h! mov d,m xchg! mov a,l! ora h! rz jmp discard1 else push h lxi d,adrive! call compare pop h! rnz mvi m,0ffh! ret endif get$buffa: push d! lxi d,10! dad d mov e,m! inx h! mov d,m if BANKED inx h! mov a,m! sta buffer$bank endif xchg! pop d! ret rddir: ; Read a directory entry into the directory buffer call seek$dir mvi a,3! jmp wrdir0 seek$copy: wrdir: ; Write the current directory entry, set checksum call check$write call newchecksum ; Initialize entry mvi a,5 wrdir0: lxi h,0! shld last$block lhld dirbcba if BANKED cpi 5! jnz $+6 lhld curbcba endif call deblock setdata: ; Set data dma address lhld dmaad! jmp setdma ; to complete the call setdir1: call get$buffa setdma: ; hl=.dma address to set (i.e., buffa or dmaad) shld curdma! ret dir$to$user: if not MPM ; Copy the directory entry to the user buffer ; after call to search or searchn by user code lhld buffa! xchg ; source is directory buffer lhld xdmaad ; destination is user dma address lxi b,recsiz ; copy entire record call movef endif ; Set lret to dcnt & 3 if search successful lxi h,lret! mov a,m! inr a! rz lda dcnt! ani dskmsk! mov m,a! ret make$fcb$inv: ; Flag fcb as invalid ; Reset fcb write flag call setfwf ; Set 1st two bytes of diskmap to ffh inx h! inx h! mvi a,0ffh! mov m,a! inx h! mov m,a ret chk$inv$fcb: ; Check for invalid fcb call getdma! jmp test$ffff tst$inv$fcb: ; Test for invalid fcb call chk$inv$fcb! rnz pop h! mvi a,9! jmp sta$ret! ; lret = 9 end$of$dir: ; Return zero flag if at end of directory, non zero ; if not at end (end of dir if dcnt = 0ffffh) lxi h,dcnt test$ffff: mov a,m ; may be 0ffh inx h! cmp m ; low(dcnt) = high(dcnt)? rnz ; non zero returned if different ; high and low the same, = 0ffh? inr a ; 0ffh becomes 00 if so ret set$end$dir: ; Set dcnt to the end of the directory lxi h,enddir! shld dcnt! ret read$dir: call r$dir! jmp r$dir1 r$dir: ; Read next directory entry, with c=true if initializing lhld dirmax! xchg ; in preparation for subtract lhld dcnt! inx h! shld dcnt ; dcnt=dcnt+1 ; Continue while dirmax >= dcnt (dirmax-dcnt no cy) call subdh ; de-hl jc set$end$dir read$dir0: ; not at end of directory, seek next element ; initialization flag is in c lda dcnt! ani dskmsk ; low(dcnt) and dskmsk mvi b,fcbshf ; to multiply by fcb size read$dir1: add a! dcr b! jnz read$dir1 ; a = (low(dcnt) and dskmsk) shl fcbshf sta dptr ; ready for next dir operation ora a! rnz ; Return if not a new record read$dir2: push b ; Save initialization flag c call rd$dir ; Read the directory record pop b ; Recall initialization flag lda relog! ora a! rnz jmp checksum ; Checksum the directory elt r$dir2: call read$dir2 r$dir1: lda relog! ora a! rz call chk$exit$fxs call tst$relog! jmp rd$dir getallocbit: ; Given allocation vector position bc, return with byte ; containing bc shifted so that the least significant ; bit is in the low order accumulator position. hl is ; the address of the byte for possible replacement in ; memory upon return, and d contains the number of shifts ; required to place the returned value back into position mov a,c! ani 111b! inr a! mov e,a! mov d,a ; d and e both contain the number of bit positions to shift mov h,b! mov l,c! mvi c,3 ; bc = bc shr 3 call hlrotr ; hlrotr does not touch d and e mov b,h! mov c,l lhld alloca ; base address of allocation vector dad b! mov a,m ; byte to a, hl = .alloc(bc shr 3) ; Now move the bit to the low order position of a rotl: rlc! dcr e! jnz rotl! ret setallocbit: ; bc is the bit position of alloc to set or reset. the ; value of the bit is in register e. push d! call getallocbit ; shifted val a, count in d ani 1111$1110b ; mask low bit to zero (may be set) pop b! ora c ; low bit of c is masked into a ; jmp rotr ; to rotate back into proper position ; ret rotr: ; byte value from alloc is in register a, with shift count ; in register c (to place bit back into position), and ; target alloc position in registers hl, rotate and replace rrc! dcr d! jnz rotr ; back into position mov m,a ; back to alloc ret copy$alv: ; If Z flag set, copy 1st ALV to 2nd ; Otherwise, copy 2nd ALV to 1st if not BANKED lda bdos$flags! rlc! rlc! rc endif push a call get$nalbs! mov b,h! mov c,l lhld alloca! mov d,h! mov e,l! dad b pop a! jz movef xchg! jmp movef scandm$ab: ; Set/Reset 1st and 2nd ALV push b! call scandm$a pop b! ;jmp scandm$b scandm$b: ; Set/Reset 2nd ALV if not BANKED lda bdos$flags! ani 40h! rnz endif push b! call get$nalbs xchg! lhld alloca pop b! push h! dad d! shld alloca call scandm$a pop h! shld alloca! ret scandm$a: ; Set/Reset 1st ALV ; Scan the disk map addressed by dptr for non-zero ; entries, the allocation vector entry corresponding ; to a non-zero entry is set to the value of c (0,1) call getdptra ; hl = buffa + dptr ; hl addresses the beginning of the directory entry lxi d,dskmap! dad d ; hl now addresses the disk map push b ; Save the 0/1 bit to set mvi c,fcblen-dskmap+1 ; size of single byte disk map + 1 scandm0: ; Loop once for each disk map entry pop d ; Recall bit parity dcr c! rz ; all done scanning? ; no, get next entry for scan push d ; Replace bit parity lda single! ora a! jz scandm1 ; single byte scan operation push b ; Save counter push h ; Save map address mov c,m! mvi b,0 ; bc=block# jmp scandm2 scandm1: ; double byte scan operation dcr c ; count for double byte push b ; Save counter mov c,m! inx h! mov b,m ; bc=block# push h ; Save map address scandm2: ; Arrive here with bc=block#, e=0/1 mov a,c! ora b ; Skip if = 0000 jz scandm3 lhld maxall ; Check invalid index mov a,l! sub c! mov a,h! sbb b ; maxall - block# cnc set$alloc$bit ; bit set to 0/1 scandm3: pop h! inx h ; to next bit position pop b ; Recall counter jmp scandm0 ; for another item get$nalbs: ; Get # of allocation vector bytes lhld maxall! mvi c,3 ; number of bytes in allocation vector is (maxall/8)+1 call hlrotr! inx h! ret if MPM test$dir: call home call set$end$dir test$dir1: mvi c,0feh! call read$dir lda flushed! ora a! rnz call end$of$dir! rz jmp test$dir1 endif initialize: ; Initialize the current disk ; lret = false ; set to true if $ file exists ; Compute the length of the allocation vector - 2 if MPM lhld tlog! call test$vector! jz initialize1 lhld tlog! call remove$drive! shld tlog xra a! sta flushed call test$dir! rz initialize1: else call test$media$flag! mvi m,0 ; Reset media change flag call discard$data call discard$dir endif if BANKED ; Is drive permanent with no chksum vector? call chksiz$eq$8000h! jnz initialize2 ; no ; Is this an initial login operation? ; register A = 0 lhld lsn$add! cmp m! mvi m,2! jz initialize2 ; yes jmp copy$alv ; Copy 2nd ALV to 1st ALV initialize2: endif call get$nalbs ; Get # of allocation vector bytes mov b,h! mov c,l ; Count down bc til zero lhld alloca ; base of allocation vector ; Fill the allocation vector with zeros initial0: mvi m,0! inx h ; alloc(i)=0 dcx b ; Count length down mov a,b! ora c! jnz initial0 lhld drvlbla! mov m,a ; Zero out drive desc byte ; Set the reserved space for the directory lhld dirblk! xchg lhld alloca ; hl=.alloc() mov m,e! inx h! mov m,d ; sets reserved directory blks ; allocation vector initialized, home disk call home ; cdrmax = 3 (scans at least one directory record) lhld cdrmaxa! mvi m,4! inx h! mvi m,0 call set$end$dir ; dcnt = enddir lhld hashtbla! shld arecord1 ; Read directory entries and check for allocated storage initial2: mvi c,true! call read$dir call end$of$dir! jz copy$alv ; not end of directory, valid entry? call getdptra ; hl = buffa + dptr xchg! lhld arecord1! mov a,h! ana l! inr a! xchg ; is hashtbla ~= 0ffffh cnz init$hash ; yes - call init$hash mvi a,21h! cmp m jz initial2 ; Skip date & time records mvi a,empty! cmp m jz initial2 ; go get another item mvi a,20h! cmp m! jz drv$lbl mvi a,10h! ana m! jnz initial3 ; Now scan the disk map for allocated blocks mvi c,1 ; set to allocated call scandm$a initial3: call setcdr ; set cdrmax to dcnt jmp initial2 ; for another entry drv$lbl: lxi d,extnum! dad d! mov a,m lhld drvlbla! mov m,a! jmp initial3 copy$dirloc: ; Copy directory location to lret following ; delete, rename, ... ops lda dirloc! jmp sta$ret ; ret compext: ; Compare extent# in a with that in c, return nonzero ; if they do not match push b ; Save c's original value push psw! lda extmsk! cma! mov b,a ; b has negated form of extent mask mov a,c! ana b! mov c,a ; low bits removed from c pop psw! ana b ; low bits removed from a sub c! ani maxext ; Set flags pop b ; Restore original values ret get$dir$ext: ; Compute directory extent from fcb ; Scan fcb disk map backwards call getfcba ; hl = .fcb(vrecord) mvi c,16! mov b,c! inr c! push b ; b=dskmap pos (rel to 0) get$de0: pop b dcr c xra a ; Compare to zero get$de1: dcx h! dcr b; Decr dskmap position cmp m! jnz get$de2 ; fcb(dskmap(b)) ~= 0 dcr c! jnz get$de1 ; c = 0 -> all blocks = 0 in fcb disk map get$de2: mov a,c! sta dminx lda single! ora a! mov a,b jnz get$de3 rar ; not single, divide blk idx by 2 get$de3: push b! push h ; Save dskmap position & count mov l,a! mvi h,0 ; hl = non-zero blk idx ; Compute ext offset from last non-zero ; block index by shifting blk idx right ; 7 - blkshf lda blkshf! mov d,a! mvi a,7! sub d mov c,a! call hlrotr! mov b,l ; b = ext offset lda extmsk! cmp b! pop h! jc get$de0 ; Verify computed extent offset <= extmsk call getexta! mov c,m cma! ani maxext! ana c! ora b ; dir ext = (fcb ext & (~ extmsk) & maxext) | ext offset pop b ; Restore stack ret ; a = directory extent searchi: ; search initialization lhld info! shld searcha ; searcha = info searchi1: mov a,c! sta searchl ; searchl = c call set$hash mvi a,0ffh! sta dirloc ; changed if actually found ret search$namlen: mvi c,namlen! jmp search search$extnum: mvi c,extnum search: ; Search for directory element of length c at info call searchi search1: ; entry point used by rename call set$end$dir ; dcnt = enddir call tst$log$fxs! cz home ; (drop through to searchn) searchn: ; Search for the next directory element, assuming ; a previous call on search which sets searcha and ; searchl if MPM lxi h,user0$pass! xra a! cmp m! mov m,a! cnz swap else xra a! sta user0$pass endif call search$hash! jnz search$fin mvi c,false! call read$dir ; Read next dir element call end$of$dir! jz search$fin ; not end of directory, scan for match lhld searcha! xchg ; de=beginning of user fcb ldax d ; first character cpi empty ; Keep scanning if empty jz searchnext ; not empty, may be end of logical directory push d ; Save search address call compcdr ; past logical end? pop d ; Recall address jnc search$fin ; artificial stop searchnext: call getdptra ; hl = buffa+dptr lda searchl! mov c,a ; length of search to c mvi b,0 ; b counts up, c counts down mov a,m! cpi empty! cz save$dcnt$pos1 if BANKED xra a! sta save$xfcb mov a,m! ani 1110$1111b! cmp m! jz search$loop xchg! cmp m! xchg! jnz search$loop lda find$xfcb! ora a! jz search$n sta save$xfcb! jmp searchok endif searchloop: mov a,c! ora a! jz endsearch ldax d! cpi '?'! jz searchok ; ? in user fcb ; Scan next character if not ubytes mov a,b! cpi ubytes! jz searchok ; not the ubytes field, extent field? cpi extnum ; may be extent field jz searchext ; Skip to search extent cpi modnum! ldax d! cz searchmod sub m! ani 7fh ; Mask-out flags/extent modulus jnz searchnm ; Skip if not matched jmp searchok ; matched character searchext: ldax d ; Attempt an extent # match push b ; Save counters if MPM push h lhld sdcnt inr h! jnz dont$save lhld dcnt! shld sdcnt lhld dblk! shld sdblk dont$save: pop h endif mov c,m ; directory character to c call compext ; Compare user/dir char mov b,a lda user0pass! inr a! jz save$dcnt$pos2 ; Disable search of user 0 if any fcb ; is found under the current user # xra a! sta search$user0 mov a,b pop b ; Recall counters ora a ; Set flag jnz searchn ; Skip if no match searchok: ; current character matches inx d! inx h! inr b! dcr c jmp searchloop endsearch: ; entire name matches, return dir position if BANKED lda save$xfcb! inr a! jnz endsearch1 lda xdcnt+1! cpi 0feh! cz save$dcnt$pos0 jmp searchn endsearch1: endif xra a! sta dirloc ; dirloc = 0 sta lret ; lret = 0 ; successful search - ; return with zero flag reset mov b,a! inr b! ret searchmod: ani 3fh! ret ; Mask off high 2 bits search$fin: ; end of directory, or empty name call save$dcnt$pos1 ; Set dcnt = 0ffffh call set$end$dir ; may be artifical end lret$eq$ff: ; unsuccessful search - ; return with zero flag set ; lret,low(aret) = 0ffh mvi a,255! mov b,a! inr b! jmp sta$ret searchnm: ; search no match routine mov a,b! ora a! jnz searchn ; fcb(0)? mov a,m! ora a! jnz searchn ; dir fcb(0)=0? lda search$user0! ora a! jz searchn sta user0$pass if MPM call swap endif jmp searchok if MPM swap: ; Swap dcnt,sdblk with sdcnt0,sdblk0 push h! push d! push b lxi d,sdcnt! lxi h,sdcnt0 mvi b,4 swap1: ldax d! mov c,a! mov a,m stax d! mov m,c inx h! inx d! dcr b! jnz swap1 pop b! pop d! pop h! ret endif save$dcnt$pos2: ; Save directory position of matching fcb ; under user 0 with matching extent # & modnum = 0 ; a = 0 on entry ora b! pop b! lxi b,searchn! push b! rnz inx h! inx h! mov a,m! ora a! rnz ; Call if user0pass = 0ffh & ; dir fcb(extnum) = fcb(extnum) ; dir fcb(modnum) = 0 save$dcnt$pos0: call save$dcnt$pos ; Return to searchn save$dcnt$pos1: ; Save directory position of first empty fcb ; or the end of the directory push h! lhld xdcnt! inr h! jnz save$dcnt$pos$ret ; Return if h ~= 0ffh save$dcnt$pos: lhld dcnt! shld xdcnt if MPM lhld dblk! shld xdblk endif save$dcnt$pos$ret: pop h! ret if BANKED init$xfcb$search: mvi a,0ffh init$xfcb$search1: sta find$xfcb! mvi a,0feh! sta xdcnt+1! ret does$xfcb$exist: lda xdcnt+1! cpi 0feh! rz call set$dcnt$dblk xra a! call init$xfcb$search1 lhld searcha! mov a,m! ori 10h! mov m,a mvi c,extnum! call searchi1! jmp searchn xdcnt$eq$dcnt: lhld dcnt! shld xdcnt! ret restore$dir$fcb: call set$dcnt$dblk mvi c,namlen! call searchi! jmp searchn endif delete: ; Delete the currently addressed file call get$atts if BANKED sta attributes ; Make search return matching fcbs and xfcbs deletex: mvi a,0feh! call init$xfcb$search1 else ; Return with aret = 0 for XFCB only delete ; in non-banked systems ral! rc endif ; Delete pass 1 - check r/o attributes and xfcb passwords call search$extnum! rz delete00: jz delete1 if BANKED ; Is addressed dir fcb an xfcb? call getdptra! mov a,m! ani 10h! jnz delete01 ; yes if MPM call tst$olist ; Verify fcb not open by someone else endif ; Check r/o attribute if this is not an ; xfcb only delete operation. lda attributes! ral! cnc check$rodir else call check$rodir endif if BANKED ; Are xfcb passwords enabled? call get$dir$mode! ral! jc delete02 ; no endif ; Is this a wild card delete operation? lhld info! call chk$wild! jz delete02 ; yes ; Not wild & passwords inactive ; Skip to pass 2 jmp delete11 if BANKED delete01: ; Check xfcb password if passwords enabled call get$dir$mode! ral! jnc delete02 call chk$xfcb$password! jz delete02 call chk$pw$error! jmp deletex endif delete02: call searchn! jmp delete00 ; Delete pass 2 - delete all matching fcbs and/or xfcbs. delete1: call search$extnum delete10: jz copy$dir$loc delete11: call getdptra if BANKED ; Is addressed dir fcb an xfcb? mov a,m! ani 10h! jnz delete12 ; yes if MPM push h call chk$olist ; Delete olist item if present pop h endif ; Is this delete operation xfcb only? lda attributes! ani 80h! jnz delete13 ; yes endif delete12: ; Delete dir fcb or xfcb ; if fcb free all alocated blocks. mvi m,empty if BANKED delete13: push a ; Z flag set => free FCB blocks ; Zero password mode byte in sfcb if sfcb exists ; Does sfcb exist? call get$dtba$8! ora a! jnz $+4 ; no ; Zero mode byte mov m,a endif call wrdir! mvi c,0 if BANKED pop a! cz scandm$ab else call scandm$ab endif call fix$hash call searchn! jmp delete10 get$block: ; Given allocation vector position bc, find the zero bit ; closest to this position by searching left and right. ; if found, set the bit to one and return the bit position ; in hl. if not found (i.e., we pass 0 on the left, or ; maxall on the right), return 0000 in hl mov d,b! mov e,c ; copy of starting position to de righttst: lhld maxall ; value of maximum allocation# mov a,e! sub l! mov a,d! sbb h ; right=maxall? jnc retblock0 ; return block 0000 if so inx d! push b! push d ; left, right pushed mov b,d! mov c,e ; ready right for call call getallocbit rar! jnc retblock ; Return block number if zero pop d! pop b ; Restore left and right pointers lefttst: mov a,c! ora b! jz righttst ; Skip if left=0000 ; left not at position zero, bit zero? dcx b! push d! push b ; left,right pushed call getallocbit rar! jnc retblock ; return block number if zero ; bit is one, so try the right pop b! pop d ; left, right restored jmp righttst retblock: ral! inr a ; bit back into position and set to 1 ; d contains the number of shifts required to reposition call rotr ; move bit back to position and store pop h! pop d ; hl returned value, de discarded ret retblock0: ; cannot find an available bit, return 0000 mov a,c ora b! jnz lefttst ; also at beginning lxi h,0000h! ret copy$dir: ; Copy fcb information starting at c for e bytes ; into the currently addressed directory entry mvi d,80h copy$dir0: call copy$dir2 inr c copy$dir1: dcr c! jz seek$copy mov a,m! ana b! push b mov b,a! ldax d! ani 7fh! ora b! mov m,a pop b! inx h! inx d! jmp copy$dir1 copy$dir2: push d ; Save length for later mvi b,0 ; double index to bc lhld info ; hl = source for data dad b inx h! mov a,m! sui '$'! cz set$submit$flag dcx h! xchg ; de=.fcb(c), source for copy call getdptra ; hl=.buff(dptr), destination pop b ; de=source, hl=dest, c=length ret set$submit$flag: lxi d,ccp$flgs! ldax d! ori 1! stax d! ret check$wild: ; Check for ? in file name or type lhld info check$wild0: ; entry point used by rename call chk$wild! rnz mvi a,9! jmp set$aret chk$wild: mvi c,11 chk$wild1: inx h! mvi a,3fh! sub m! ani 7fh! rz dcr c! jnz chk$wild1! ora a! ret copy$user$no: lhld info! mov a,m! lxi b,dskmap dad b! mov m,a! ret rename: ; Rename the file described by the first half of ; the currently addressed file control block. The ; new name is contained in the last half of the ; currently addressed file control block. The file ; name and type are changed, but the reel number ; is ignored. The user number is identical. ; Verify that the new file name does not exist. ; Also verify that no wild chars exist in ; either filename. if MPM call getatts! sta attributes endif ; Verify that no wild chars exist in 1st filename. call check$wild if BANKED ; Check password of file to be renamed. call chk$password! cnz chk$pw$error ; Setup search to scan for xfcbs. call init$xfcb$search endif ; Copy user number to 2nd filename call copy$user$no shld searcha ; Verify no wild chars exist in 2nd filename call check$wild0 ; Verify new filename does not already exist mvi c,extnum! lhld searcha! call searchi1! call search1 jnz file$exists ; New filename exists if BANKED ; If an xfcb exists for the new filename, delete it. call does$xfcb$exist! cnz delete11 endif call copy$user$no if BANKED call init$xfcb$search endif ; Search up to the extent field call search$extnum rz call check$rodir ; may be r/o file if MPM call chk$olist endif ; Copy position 0 rename0: ; not end of directory, rename next element mvi c,dskmap! mvi e,extnum! call copy$dir ; element renamed, move to next call fix$hash call searchn jnz rename0 rename1: if BANKED call does$xfcb$exist! jz copy$dir$loc call copy$user$no! jmp rename0 else jmp copy$dir$loc endif indicators: ; Set file indicators for current fcb call get$atts ; Clear f5' through f8' sta attributes if BANKED call chk$password! cnz chk$pw$error endif call search$extnum ; through file type rz if MPM call chk$olist endif indic0: ; not end of directory, continue to change mvi c,0! mvi e,extnum ; Copy name call copy$dir2! call move lda attributes! ani 40h! jz indic1 ; If interface att f6' set, dir fcb(s1) = fcb(cr) push h! call getfcba! mov a,m pop h! inx h! mov m,a indic1: call seek$copy call searchn jz copy$dir$loc jmp indic0 open: ; Search for the directory entry, copy to fcb call search$namlen open1: rz ; Return with lret=255 if end ; not end of directory, copy fcb information open$copy: call setfwf! mov e,a! push h! dcx h! dcx h mov d,m! push d ; Save extent# & module# with fcb write flag set call getdptra! xchg ; hl = .buff(dptr) lhld info ; hl=.fcb(0) mvi c,nxtrec ; length of move operation call move ; from .buff(dptr) to .fcb(0) ; Note that entire fcb is copied, including indicators call get$dir$ext! mov c,a ; Restore module # and extent # pop d! pop h! mov m,e! dcx h! dcx h! mov m,d ; hl = .user extent#, c = dir extent# ; above move set fcb(reccnt) to dir(reccnt) ; if fcb ext < dir ext then fcb(reccnt) = fcb(reccnt) | 128 ; if fcb ext = dir ext then fcb(reccnt) = fcb(reccnt) ; if fcb ext > dir ext then fcb(reccnt) = 0 set$rc: ; hl=.fcb(ext), c=dirext mvi b,0 xchg! lxi h,(reccnt-extnum)! dad d ; Is fcb ext = dirext? ldax d! sub c! jz set$rc2 ; yes ; Is fcb ext > dirext? mov a,b! jnc set$rc1 ; yes - fcb(rc) = 0 ; fcb ext < dirext ; fcb(rc) = 128 | fcb(rc) mvi a,128! ora m set$rc1: mov m,a! ret set$rc2: ; fcb ext = dirext mov a,m! ora a! rnz ; ret if fcb(rc) ~= 0 set$rc3: mvi m,0 ; required by function 99 lda dminx! ora a! rz ; ret if no blks in fcb mvi m,128! ret ; fcb(rc) = 128 mergezero: ; hl = .fcb1(i), de = .fcb2(i), ; if fcb1(i) = 0 then fcb1(i) := fcb2(i) mov a,m! inx h! ora m! dcx h! rnz ; return if = 0000 ldax d! mov m,a! inx d! inx h ; low byte copied ldax d! mov m,a! dcx d! dcx h ; back to input form ret restore$rc: ; hl = .fcb(extnum) ; if fcb(rc) > 80h then fcb(rc) = fcb(rc) & 7fh push h lxi d,(reccnt-extnum)! dad d mov a,m! cpi 81h! jc restore$rc1 ani 7fh! mov m,a restore$rc1: pop h! ret close: ; Locate the directory element and re-write it xra a! sta lret if MPM sta dont$close endif call nowrite! rnz ; Skip close if r/o disk ; Check file write flag - 0 indicates written call getmodnum ; fcb(modnum) in a ani fwfmsk! rnz ; Return if bit remains set close1: call chk$inv$fcb! jz mergerr if MPM call set$fcb$cks$flag endif call get$dir$ext! mov c,a mov b,m! push b ; b = original extent, c = directory extent ; Set fcb(ex) to directory extent mov m,c ; Recompute fcb(rc) call restore$rc ; Call set$rc if fcb ext > dir ext mov a,c! cmp b! cc set$rc call close$fcb ; Restore original extent & reset fcb(rc) call get$exta! pop b mov c,m! mov m,b! jmp set$rc ; Reset fcb(rc) close$fcb: ; Locate file call search$namlen rz ; Return if not found ; Merge the disk map at info with that at buff(dptr) lxi b,dskmap! call get$fcb$adds mvi c,(fcblen-dskmap) ; length of single byte dm merge0: lda single! ora a! jz merged ; Skip to double ; This is a single byte map ; if fcb(i) = 0 then fcb(i) = buff(i) ; if buff(i) = 0 then buff(i) = fcb(i) ; if fcb(i) <> buff(i) then error mov a,m! ora a! ldax d! jnz fcbnzero ; fcb(i) = 0 mov m,a ; fcb(i) = buff(i) fcbnzero: ora a! jnz buffnzero ; buff(i) = 0 mov a,m! stax d ; buff(i)=fcb(i) buffnzero: cmp m! jnz mergerr ; fcb(i) = buff(i)? jmp dmset ; if merge ok merged: ; This is a double byte merge operation call mergezero ; buff = fcb if buff 0000 xchg! call mergezero! xchg ; fcb = buff if fcb 0000 ; They should be identical at this point ldax d! cmp m! jnz mergerr ; low same? inx d! inx h ; to high byte ldax d! cmp m! jnz mergerr ; high same? ; merge operation ok for this pair dcr c ; extra count for double byte dmset: inx d! inx h ; to next byte position dcr c! jnz merge0 ; for more ; end of disk map merge, check record count ; de = .buff(dptr)+32, hl = .fcb(32) xchg! lxi b,-(fcblen-extnum)! dad b! push h call get$dir$ext! pop d ; hl = .fcb(extnum), de = .buff(dptr+extnum) call compare$extents ; b=1 -> fcb(ext) ~= dir ext = buff(ext) ; b=2 -> fcb(ext) = dir ext ~= buff(ext) ; b=3 -> fcb(ext) = dir ext = buff(ext) ; fcb(ext), buff(ext) = dir ext mov m,a! stax d! push b lxi b,(reccnt-extnum)! dad b! xchg! dad b pop b ; hl = .buff(rc) , de = .fcb(rc) dcr b! jz mrg$rc1 ; fcb(rc) = buff(rc) dcr b! jz mrg$rc2 ; buff(rc) = fcb(rc) ldax d! cmp m! jc mrg$rc1 ; Take larger rc ora a! jnz mrg$rc2 call set$rc3 mrg$rc1: xchg mrg$rc2: ldax d! mov m,a if MPM lda dont$close! ora a! rnz endif ; Set t3' off indicating file update call getdptra! lxi d,11! dad d mov a,m! ani 7fh! mov m,a call setfwf mvi c,1! call scandm$b ; Set 2nd ALV vector jmp seek$copy ; OK to "wrdir" here - 1.4 compat ; ret mergerr: ; elements did not merge correctly call make$fcb$inv jmp lret$eq$ff compare$extents: mvi b,1! cmp m! rnz inr b! xchg! cmp m! xchg! rnz inr b! ret set$xdcnt: lxi h,0ffffh! shld xdcnt! ret set$dcnt$dblk: lhld xdcnt set$dcnt$dblk1: mvi a,1111$1100b! ana l mov l,a! dcx h! shld dcnt if MPM lhld xdblk! shld dblk endif ret if MPM sdcnt$eq$xdcnt: lxi h,sdcnt! lxi d,xdcnt! mvi c,4 jmp move endif make: ; Create a new file by creating a directory entry ; then opening the file lxi h,xdcnt! call test$ffff! cnz set$dcnt$dblk lhld info! push h ; Save fcb address, Look for E5 lxi h,efcb! shld info ; info = .empty mvi c,1 call searchi! call searchn ; zero flag set if no space pop h ; Recall info address shld info ; in case we return here rz ; Return with error condition 255 if not found if BANKED ; Return early if making an xfcb lda make$xfcb! ora a! rnz endif ; Clear the remainder of the fcb ; Clear s1 byte lxi d,13! dad d! mov m,d! inx h ; Clear and save file write flag of modnum mov a,m! push a! push h! ani 3fh! mov m,a! inx h mvi a,1 mvi c,fcblen-namlen ; number of bytes to fill make0: mov m,d! inx h! dcr c! jnz make0 dcr a! mov c,d! cz get$dtba ora a! mvi c,10! jz make0 call setcdr ; may have extended the directory ; Now copy entry to the directory mvi c,0! lxi d,fcblen! call copy$dir0 ; and restore the file write flag pop h! pop a! mov m,a ; and set the fcb write flag to "1" call fix$hash jmp setfwf open$reel: ; Close the current extent, and open the next one ; if possible. rmf is true if in read mode if BANKED call reset$copy$cr$only endif call getexta mov a,m! mov c,a inr c! call compext jz open$reel3 push h! push b call close pop b! pop h lda lret! inr a! rz mvi a,maxext! ana c! mov m,a ; Incr extent field ; Advance to module & save inx h! inx h! mov a,m! sta save$mod jnz open$reel0 ; Jump if in same module open$mod: ; Extent number overflow, go to next module inr m ; fcb(modnum)=++1 ; Module number incremented, check for overflow mov a,m! ani 3fh ; Mask high order bits jz open$r$err ; cannot overflow to zero ; otherwise, ok to continue with new module open$reel0: call set$xdcnt ; Reset xdcnt for make if MPM call set$sdcnt endif call search$namlen ; Next extent found? jnz open$reel1 ; end of file encountered lda rmf! inr a ; 0ffh becomes 00 if read jz open$r$err ; sets lret = 1 ; Try to extend the current file call make ; cannot be end of directory jz open$r$err ; with lret = 1 if MPM call fix$olist$item call set$fcb$cks$flag endif jmp open$reel2 open$reel1: ; not end of file, open call open$copy if MPM call set$fcb$cks$flag endif open$reel2: if not MPM call set$lsn endif call getfcb ; Set parameters xra a! sta vrecord! jmp sta$ret ; lret = 0 ; ret ; with lret = 0 open$r$err: ; Restore module and extent call getmodnum! lda save$mod! mov m,a dcx h! dcx h! mov a,m! dcr a! ani 1fh mov m,a! jmp setlret1 ; lret = 1 open$reel3: inr m ; fcb(ex) = fcb(ex) + 1 call get$dir$ext! mov c,a ; Is new extent beyond dir$ext? cmp m! jnc open$reel4 ; no dcr m ; fcb(ex) = fcb(ex) - 1 ; Is this a read fx? lda rmf! inr a! jz set$lret1 ; yes - Don't advance ext inr m ; fcb(ex) = fcb(ex) + 1 open$reel4: call restore$rc call set$rc! jmp open$reel2 seqdiskread: diskread: ; (may enter from seqdiskread) call tst$inv$fcb ; Check for valid fcb mvi a,true! sta rmf ; read mode flag = true (open$reel) if MPM sta dont$close endif ; Read the next record from the current fcb call getfcb ; sets parameters for the read diskread0: lda vrecord! lxi h,rcount! cmp m ; vrecord-rcount ; Skip if rcount > vrecord jc recordok if MPM call test$disk$fcb! jnz diskread0 lda vrecord endif ; not enough records in the extent ; record count must be 128 to continue cpi 128 ; vrecord = 128? jnz setlret1 ; Skip if vrecord<>128 call open$reel ; Go to next extent if so ; Check for open ok lda lret! ora a! jnz setlret1 ; Stop at eof recordok: ; Arrive with fcb addressing a record to read if BANKED call set$copy$cr$only endif call index ; Z flag set if arecord = 0 if MPM jnz recordok1 call test$disk$fcb! jnz diskread0 endif jz setlret1 ; Reading unwritten data recordok1: ; Record has been allocated, read it call atran ; arecord now a disk address call check$nprs jc setfcb jnz read$deblock call setdata call seek ; to proper track,sector if BANKED mvi a,1! call setbnkf endif call rdbuff ; to dma address jmp setfcb ; Replace parameter read$deblock: lxi h,0! shld last$block mvi a,1! call deblock$dta jmp setfcb check$nprs: ; ; on exit, c flg -> no i/o operation ; z flg & ~c flg -> direct(physical) i/o operation ; ~z flg & ~c flg -> indirect(deblock) i/o operation ; ; Dir$cnt contains the number of 128 byte records ; to transfer directly. This routine sets dir$cnt ; when initiating a sequence of direct physical ; i/o operations. Dir$cnt is decremented each ; time check$nprs is called during such a sequence. ; ; Is direct transfer operation in progress? lda blk$off! mov b,a lda phy$msk! mov c,a! ana b! push a lda dir$cnt! cpi 2! jc check$npr1 ; no ; yes - Decrement direct record count dcr a! sta dir$cnt ; Are we at a new physical record? pop a! stc! rnz ; no - ret with c flg set ; Perform physical i/o operation xra a! ret ; Return with z flag set and c flag reset check$npr1: ; Are we in mid-physical record? pop a! jz check$npr11 ; no check$npr1a: ; Is phymsk = 0? mov a,c! ora a! rz ; yes - Don't deblock check$npr1b: ; Deblocking required ori 1! ret ; ret with z flg reset and c flg reset check$npr11: mov a,c! cma! mov d,a ; d = ~phy$msk lxi h,vrecord ; Is mult$num < 2? lda mult$num! cpi 2! jc check$npr1a ; yes add m! cpi 80h! jc check$npr2 mvi a,80h check$npr2: ; a = min(vrecord + mult$num),80h) = x push b ; Save low(arecord) & blkmsk, phymsk mov b,m! mvi m,7fh ; vrecord = 7f push b ; Save vrecord push h ; Save .vrecord push a ; Save x lda blkmsk! mov e,a! inr e! cma! ana b! mov b,a ; b = vrecord & ~blkmsk ; e = blkmsk + 1 pop h ; h = x ; Is this a read function? lda rmf! ora a! jz check$npr21 ; no ; Is rcount & ~phymsk < x? lda rcount! ana d! cmp h! jc check$npr23 ; yes check$npr21: mov a,h ; a = x check$npr23: sub b ; a = a - vrecord & ~blkmsk mov c,a ; c = max # of records from beginning of curr blk ; Is c < blkmsk+1? cmp e! jc check$npr8 ; yes if BANKED push b ; c = max # of records ; Compute maximum disk map position call dm$position mov b,a ; b = index of last block in extent ; Does the last block # = the current block #? lda dminx! cmp b! mov e,a! jz check$npr5 ; yes ; Compute # of blocks in sequence mov c,a! push b! mvi b,0 call get$dm ; hl = current block # check$npr4: ; Get next block # push h! inx b! call get$dm pop d! inx d ; Does next block # = previous block # + 1? mov a,d! sub h! mov d,a mov a,e! sub l! ora d! jz check$npr4 ; yes ; Is next block # = 0? mov a,h! ora l! jnz check$npr45 ; no ; Is this a read function? lda rmf! ora a! jnz check$npr45 ; no ; Is next block # > maxall? lhld maxall! mov a,l! sub e mov a,h! sbb d! jc check$npr45 ; yes ; Is next block # allocated? push b! push d! mov b,d! mov c,e call getallocbit! pop h! pop b rar! jnc check$npr4 ; no - it will be later check$npr45: dcr c! pop d ; Is max dm position less than c? mov a,d! cmp c! jc check$npr5 ; yes mov a,c ; no check$npr5: ; a = index of last block sub e! mov b,a! inr b ; b = # of consecutive blks lda blkmsk! inr a! mov c,a check$npr6: dcr b! jz check$npr7 add c! jmp check$npr6 check$npr7: pop b mov b,c ; b = max # of records mov c,a ; c = (# of consecutive blks)*(blkmsk+1) lda rmf! ora a! jz check$npr8 mov a,b! cmp c! jc check$npr9 else mov c,e ; multis-sector max = 1 block in non-banked systems endif check$npr8: mov a,c check$npr9: ; Restore vrecord pop h! pop b! mov m,b pop b ; a = max # of consecutive records including current blk ; b = low(arecord) & blkmsk ; c = phymsk ; Is mult$num > a - b lxi h,mult$num! mov d,m sub b! cmp d! jnc check$npr10 mov d,a ; yes - use smaller value to compute dir$cnt check$npr10: ; Does this operation involve at least 1 physical record? mov a,c! cma! ana d! sta dir$cnt! jz check$npr1b ; Deblocking required ; Flush any pending buffers before doing multiple reads push a! lda rmf! ora a! jz check$npr10a call flushx! call setdata check$npr10a: pop a! mov h,a ; Save # of 128 byte records ; Does this operation involve more than 1 physical record? ; Register h contains number of 128 byte records call shr$physhf! mov a,h cpi 1! mov c,a! cnz mult$iof ; yes - Make bios call xra a! ret ; Return with z flg set if MPM test$unlocked: lda high$ext! ani 80h! ret test$disk$fcb: call test$unlocked! rz lda dont$close! ora a! rz call close1 test$disk$fcb1: pop d lxi h,lret! inr m! mvi a,11! jz sta$ret mvi m,0 push d call getrcnta! mov a,m! sta rcount ; Reset rcount xra a! sta dont$close inr a! ret endif reset$fwf: call getmodnum ; hl=.fcb(modnum), a=fcb(modnum) ; Reset the file write flag to mark as written fcb ani (not fwfmsk) and 0ffh ; bit reset mov m,a ; fcb(modnum) = fcb(modnum) and 7fh ret set$filewf: call getmodnum! ani 0100$0000b! push a mov a,m! ori 0100$0000b! mov m,a! pop a! ret seqdiskwrite: diskwrite: ; (may enter here from seqdiskwrite above) mvi a,false! sta rmf ; read mode flag ; Write record to currently selected file call check$write ; in case write protected if BANKED lda xfcb$read$only! ora a mvi a,3! jnz set$aret endif lda high$ext if MPM ani 0100$0000b else ora a endif ; Z flag reset if r/o mode mvi a,3! jnz set$aret lhld info ; hl = .fcb(0) call check$rofile ; may be a read-only file call tst$inv$fcb ; Test for invalid fcb call update$stamp call getfcb ; to set local parameters lda vrecord! cpi lstrec+1 ; vrecord-128 jc diskwrite0 call open$reel ; vrecord = 128, try to open next extent lda lret! ora a! rnz ; no available fcb disk$write0: if MPM mvi a,0ffh! sta dont$close disk$write1: endif ; Can write the next record, so continue call index ; Z flag set if arecord = 0 jz diskwrite2 ; Was the last write operation for the same block & drive? lxi h,adrive! lxi d,last$drive! mvi c,3 call compare! jz diskwrite15 ; yes ; no - force preread in blocking/deblocking mvi a,0ffh! sta last$off diskwrite15: if MPM ; If file is unlocked, verify record is not locked ; Record has to be allocated to be locked call test$unlocked! jz not$unlocked call atran! mov c,a lda mult$cnt! mov b,a! push b call test$lock! pop b xra a! mov c,a! push b jmp diskwr10 not$unlocked: inr a endif mvi c,0 ; Marked as normal write operation for wrbuff jmp diskwr1 diskwrite2: if MPM call test$disk$fcb! jnz diskwrite1 endif if BANKED call reset$copy$cr$only endif ; not allocated ; The argument to getblock is the starting ; position for the disk search, and should be ; the last allocated block for this file, or ; the value 0 if no space has been allocated call dm$position sta dminx ; Save for later lxi b,0000h ; May use block zero ora a! jz nopblock ; Skip if no previous block ; Previous block exists at a mov c,a! dcx b ; Previous block # in bc call getdm ; Previous block # to hl mov b,h! mov c,l ; bc=prev block# nopblock: ; bc = 0000, or previous block # call get$block ; block # to hl ; Arrive here with block# or zero mov a,l! ora h! jnz blockok ; Cannot find a block to allocate mvi a,2! jmp sta$ret ; lret=2 blockok: if MPM call set$fcb$cks$flag endif ; allocated block number is in hl shld arecord! shld last$block! xra a! sta last$off lda adrive! sta lastdrive xchg ; block number to de lhld info! lxi b,dskmap! dad b ; hl=.fcb(dskmap) lda single! ora a ; Set flags for single byte dm lda dminx ; Recall dm index jz allocwd ; Skip if allocating word ; Allocating a byte value call addh! mov m,e ; single byte alloc jmp diskwru ; to continue allocwd: ; Allocate a word value mov c,a! mvi b,0 ; double(dminx) dad b! dad b ; hl=.fcb(dminx*2) mov m,e! inx h! mov m,d ; double wd diskwru: ; disk write to previously unallocated block mvi c,2 ; marked as unallocated write diskwr1: ; Continue the write operation of no allocation error ; c = 0 if normal write, 2 if to prev unalloc block push b ; Save write flag call atran ; arecord set diskwr10: lda fx! cpi 40! jnz diskwr11 ; fx ~= wrt rndm zero fill mov a,c! dcr a! dcr a! jnz diskwr11 ; old allocation ; write random zero fill + new block pop b! push a ; zero write flag lhld arecord! push h lxi h,phymsk! mov e,m! inr e! mov d,a! push d lhld dirbcba if BANKED mov e,m! inx h! mov d,m! xchg fill00: push h! call get$next$bcba! pop d! jnz fill00 xchg endif ; Force prereads in blocking/deblocking ; Discard BCB dcr a! sta last$off! mov m,a call setdir1 ; Set dma to BCB buffer ; Zero out BCB buffer pop d! push d! xra a fill0: mov m,a! inx h! inr d! jp fill0 mov d,a! dcr e! jnz fill0 ; Write 1st physical record of block lhld arecord1! mvi c,2 fill1: shld arecord! push b! call discard$data$bcb call seek if BANKED xra a! call setbnkf endif pop b! call wrbuff lhld arecord! pop d! push d ; Continue writing until blkmsk & arecord = 0 dad d! lda blkmsk! ana l! mvi c,0! jnz fill1 ; Restore arecord pop h! pop h! shld arecord call setdata ; Restore dma diskwr11: pop d! lda vrecord! mov d,a ; Load and save vrecord push d! call check$nprs jc dont$write jz write mvi a,2 ; deblock write code call deblock$dta jmp dont$write write: call setdata call seek if BANKED mvi a,1! call setbnkf endif ; Discard matching BCB if write is direct call discard$data$bcb ; Set write flag to zero if arecord & blkmsk ~= 0 pop b! push b! lda arecord lxi h,blkmsk! ana m! jz write0 mvi c,0 write0: call wrbuff dont$write: pop b ; c = 2 if a new block was allocated, 0 if not ; Increment record count if rcount<=vrecord mov a,b! lxi h,rcount! cmp m ; vrecord-rcount jc diskwr2 ; rcount <= vrecord mov m,a! inr m ; rcount = vrecord+1 if MPM call test$unlocked! jz write1 ; for unlocked files ; rcount = rcount & (~ blkmsk) + blkmsk + 1 lda blkmsk! mov b,a! inr b! cma! mov c,a mov a,m! dcr a! ana c! add b! mov m,a write1: endif mvi c,2 ; Mark as record count incremented diskwr2: ; a has vrecord, c=2 if new block or new record# dcr c! dcr c! jnz noupdate call reset$fwf if MPM call test$unlocked! jz noupdate lda rcount! call getrcnta! mov m,a call close call test$disk$fcb1 endif noupdate: ; Set file write flag if reset call set$filewf if BANKED jnz disk$write3 ; Reset fcb file write flag to ensure t3' gets ; reset by the close function call reset$fwf call reset$copy$cr$only jmp setfcb disk$write3: call set$copy$cr$only else cz reset$fwf endif jmp setfcb ; Replace parameters ; ret rseek: ; Random access seek operation, c=0ffh if read mode ; fcb is assumed to address an active file control block ; (1st block of FCB = 0ffffh if previous bad seek) push b ; Save r/w flag lhld info! xchg ; de will hold base of fcb lxi h,ranrec! dad d ; hl=.fcb(ranrec) mov a,m! ani 7fh! push psw ; record number mov a,m! ral ; cy=lsb of extent# inx h! mov a,m! ral! ani 11111b ; a=ext# mov c,a ; c holds extent number, record stacked mov a,m! ani 1111$0000b! inx h! ora m rrc! rrc! rrc! rrc! mov b,a ; b holds module # ; Check high byte of ran rec <= 3 mov a,m ani 1111$1100b! pop h! mvi l,6! mov a,h ; Produce error 6, seek past physical eod jnz seekerr ; otherwise, high byte = 0, a = sought record lxi h,nxtrec! dad d ; hl = .fcb(nxtrec) mov m,a ; sought rec# stored away ; Arrive here with b=mod#, c=ext#, de=.fcb, rec stored ; the r/w flag is still stacked. compare fcb values lda fx! cpi 99! jz rseek3 ; Check module # first push d! call chk$inv$fcb! pop d! jz ranclose lxi h,modnum! dad d! mov a,b ; b=seek mod# sub m! ani 3fh! jnz ranclose ; same? ; Module matches, check extent lxi h,extnum! dad d mov a,m! cmp c! jz seekok2 ; extents equal call compext! jnz ranclose ; Extent is in same directory fcb push b! call get$dir$ext! pop b cmp c! jnc rseek2 ; jmp if dir$ext > ext pop d! push d! inr e! jnz rseek2 ; jmp if write fx inr e! pop d! jmp set$lret1 ; error - reading unwritten data rseek2: mov m,c ; fcb(ext) = c mov c,a ; c = dir$ext ; hl=.fcb(ext),c=dir ext call restore$rc call set$rc jmp seekok1 ranclose: push b! push d ; Save seek mod#,ext#, .fcb call close ; Current extent closed pop d! pop b ; Recall parameters and fill mvi l,3 ; Cannot close error #3 lda lret! inr a! jz seekerr rseek3: call set$xdcnt ; Reset xdcnt for make if MPM call set$sdcnt endif lxi h,extnum! dad d! push h mov d,m! mov m,c ; fcb(extnum)=ext# inx h! inx h! mov a,m! mov e,a! push d ani 040h! ora b! mov m,a ; fcb(modnum)=mod# call open ; Is the file present? lda lret! inr a! jnz seekok ; Open successful? ; Cannot open the file, read mode? pop d! pop h! pop b ; r/w flag to c (=0ffh if read) push b! push h! push d ; Restore stack mvi l,4 ; Seek to unwritten extent #4 inr c ; becomes 00 if read operation jz badseek ; Skip to error if read operation ; Write operation, make new extent call make mvi l,5 ; cannot create new extent #5 jz badseek ; no dir space if MPM call fix$olist$item endif ; file make operation successful seekok: pop b! pop b ; Discard top 2 stacked items if MPM call set$fcb$cks$flag else call set$lsn endif seekok1: if BANKED call reset$copy$cr$only endif seekok2: pop b ; Discard r/w flag or .fcb(ext) xra a! jmp sta$ret ; with zero set badseek: ; Restore fcb(ext) & fcb(mod) pop d! xthl ; Save error flag mov m,d! inx h! inx h! mov m,e pop h ; Restore error flag seekerr: if BANKED call reset$copy$cr$only ; Z flag set inr a ; Reset Z flag endif pop b ; Discard r/w flag mov a,l! jmp sta$ret ; lret=#, nonzero randiskread: ; Random disk read operation mvi c,true ; marked as read operation call rseek cz diskread ; if seek successful ret randiskwrite: ; Random disk write operation mvi c,false ; marked as write operation call rseek cz diskwrite ; if seek successful ret compute$rr: ; Compute random record position for getfilesize/setrandom xchg! dad d ; de=.buf(dptr) or .fcb(0), hl = .f(nxtrec/reccnt) mov c,m! mvi b,0 ; bc = 0000 0000 ?rrr rrrr lxi h,extnum! dad d! mov a,m! rrc! ani 80h ; a=e000 0000 add c! mov c,a! mvi a,0! adc b! mov b,a ; bc = 0000 000? errrr rrrr mov a,m! rrc! ani 0fh! add b! mov b,a ; bc = 000? eeee errrr rrrr lxi h,modnum! dad d! mov a,m ; a=xxmm mmmm add a! add a! add a! add a ; cy=m a=mmmm 0000 ora a! add b! mov b,a! push psw ; Save carry mov a,m! rar! rar! rar! rar! ani 0000$0011b ; a=0000 00mm mov l,a! pop psw! mvi a,0! adc l ; Add carry ret compare$rr: mov e,a ; Save cy mov a,c! sub m! mov d,a! inx h ; lst byte mov a,b! sbb m! inx h ; middle byte push a! ora d! mov d,a! pop a mov a,e! sbb m ; carry if .fcb(ranrec) > directory ret set$rr: mov m,e! dcx h! mov m,b! dcx h! mov m,c! ret getfilesize: ; Compute logical file size for current fcb ; Zero the receiving ranrec field call get$rra! push h ; Save position mov m,d! inx h! mov m,d! inx h! mov m,d ; =00 00 00 call search$extnum getsize: jz setsize ; current fcb addressed by dptr call getdptra! lxi d,reccnt ; ready for compute size call compute$rr ; a=0000 00mm bc = mmmm eeee errr rrrr ; Compare with memory, larger? pop h! push h ; Recall, replace .fcb(ranrec) call compare$rr! cnc set$rr call searchn mvi a,0! sta aret jmp getsize setsize: pop h ; Discard .fcb(ranrec) ret setrandom: ; Set random record from the current file control block xchg! lxi d,nxtrec ; Ready params for computesize call compute$rr ; de=info, a=0000 00mm, bc=mmmm eeee errr rrrr lxi h,ranrec! dad d ; hl = .fcb(ranrec) mov m,c! inx h! mov m,b! inx h! mov m,a ; to ranrec ret disk$select: ; Select disk info for subsequent input or output ops sta adrive disk$select1: ; called by deblock mov m,a ; curdsk = seldsk or adrive mov d,a ; Save seldsk in register D for selectdisk call lhld dlog! call test$vector ; test$vector does not modify DE mov e,a! push d ; Send to seldsk, save for test below call selectdisk! pop h ; Recall dlog vector jnc sel$error ; returns with C flag set if select ok ; Is the disk logged in? dcr l ; reg l = 1 if so ret tmpselect: lxi h,seldsk! mov m,e curselect: lda seldsk! lxi h,curdsk! cmp m! jnz select cpi 0ffh! rnz ; return if seldsk ~= ffh select: call disk$select if MPM jnz select1 ; no ; yes - drive previously logged in lhld rlog! call test$vector sta rem$drv! ret ; Set rem$drv & return select1: else rz ; yes - drive previously logged in endif call initialize ; Log in the directory ; Increment login sequence # if odd lhld lsn$add! mov a,m! ani 1! push a! add m! mov m,a pop a! cnz set$rlog call set$dlog if MPM lxi h,chksiz+1! mov a,m! ral! mvi a,0! jc select2 lxi d,rlog! call set$cdisk ; rlog=set$cdisk(rlog) mvi a,1 select2: sta rem$drv endif ret reselectx: xra a! sta high$ext if BANKED sta xfcb$read$only endif jmp reselect1 reselect: ; Check current fcb to see if reselection necessary lxi b,807fh lhld info! lxi d,7! xchg! dad d if BANKED ; xfcb$read$only = 80h & fcb(7) mov a,m! ana b! sta xfcb$read$only ; fcb(7) = fcb(7) & 7fh mov a,m! ana c! mov m,a endif if MPM ; if fcb(8) & 80h ; then fcb(8) = fcb(8) & 7fh, high$ext = 60h ; else high$ext = fcb(ext) & 0e0h inx h! lxi d,4 mov a,m! ana c! cmp m! mov m,a! mvi a,60h! jnz reselect0 dad d! mvi a,0e0h! ana m reselect0: sta high$ext else ; high$ext = 80h & fcb(8) inx h! mov a,m! ana b! sta high$ext ; fcb(8) = fcb(8) & 7fh mov a,m! ana c! mov m,a endif ; fcb(ext) = fcb(ext) & 1fh call clr$ext reselect1: lxi h,0 if BANKED shld make$xfcb ; make$xfcb,find$xfcb = 0 endif shld xdcnt ; required by directory hashing xra a! sta search$user0 dcr a! sta resel ; Mark possible reselect lhld info! mov a,m ; drive select code sta fcbdsk ; save drive code ani 1$1111b ; non zero is auto drive select dcr a ; Drive code normalized to 0..30, or 255 sta linfo ; Save drive code cpi 0ffh! jz noselect ; auto select function, seldsk saved above sta seldsk noselect: call curselect ; Set user code lda usrcode ; 0...15 lhld info! mov m,a noselect0: ; Discard directory BCB's if drive is removable ; and fx = 15,17,19,22,23,30 etc. call tst$log$fxs! cz discard$dir ; Check for media change on currently slected disk call check$media ; Check for media change on any other disks jmp check$all$media check$media: ; Check media if DPH media flag set. ; Is DPH media flag set? call test$media$flag! rz ; no ; Test for media change by reading directory ; to current high water mark or until media change ; is detected. ; First reset DPH media flag & discard directory BCB's mvi m,0 call discard$dir lhld dcnt! push h call home! call set$end$dir check$media1: mvi c,false! call r$dir lxi h,relog! mov a,m! ora a! jz check$media2 mvi m,0! pop h! lda fx! cpi 48! rz call drv$relog! jmp chk$exit$fxs check$media2: call comp$cdr! jc check$media1 pop h! shld dcnt! ret check$all$media: ; This routine checks all logged-in drives for ; a set DPH media flag and pending buffers. It reads ; the directory for these drives to verify that media ; has not changed. If media has changed, the drives ; get reset (but not relogged-in). ; Is SCB media flag set? lxi h,media$flag! mov a,m! ora a! rz ; no ; Reset SCB media flag mvi m,0 ; Test logged-in drives only lhld dlog! mvi a,16 chk$am1: dcr a! dad h! jnc chk$am2 ; A = drive # ; Select drive push a! push h! lxi h,curdsk! call disk$select ; Does drive have pending data buffers? call test$pending! cnz check$media ; yes pop h! pop a chk$am2: ora a! jnz chk$am1 jmp curselect test$pending: ; On return, Z flag reset if buffer pending ; Does dta$bcba = 0ffffh lhld dta$bcba! mov a,l! ana h! inr a! rz ; yes if BANKED test$p1: ; Does bcb addr = 0? mov e,m! inx h! mov d,m mov a,e! ora d! rz ; yes - no pending buffers lxi h,4 else lxi d,4 endif ; Is buffer pending? dad d! mov a,m! ora a ; A ~= 0 if so if BANKED rnz ; yes ; no - advance to next bcb lxi h,13! dad d! jmp test$p1 else ret endif get$dir$mode: lhld drvlbla! mov a,m if not BANKED ani 7fh ; Mask off password bit endif ret if BANKED chk$password: call get$dir$mode! ani 80h! rz chk$pw: ; Check password call get$xfcb! rz ; a = xfcb options jmp cmp$pw chk$pw$error: ; Disable special searches xra a! sta xdcnt+1 ; pw$fcb = dir$xfcb call getdptra! xchg mvi c,12! lxi h,pw$fcb! push h call move! ldax d! inx h! mov m,a! pop d lhld info! mov a,m! stax d ; push original info and xfcb password mode ; info = .pw$fcb push h! xchg! shld info ; Does fcb(ext = 0, mod = 0) exist? call search$namlen! jz chk$pwe2 ; no ; Does sfcb exist for fcb ? call get$dtba$8! ora a! jnz chk$pwe1 ; no xchg! lxi h,pw$mode ; Is sfcb password mode nonzero? mov b,m! ldax d! mov m,a! ora a! jz chk$pwe2 ; no ; Do password modes match? xra b! ani 0e0h! jz chk$pwe1 ; yes ; no - update xfcb to match sfcb call get$xfcb! jz chk$pwe1 ; no xfcb (error) lda pw$mode! mov m,a! call nowrite! cz seek$copy chk$pwe1: pop h! shld info lda fx! cpi 15! rz! cpi 22! rz pw$error: ; password error mvi a,7! jmp set$aret chk$pwe2: xra a! sta pw$mode call nowrite! jnz chk$pwe3 ; Delete xfcb call get$xfcb! push a lhld info! mov a,m! ori 10h! mov m,a pop a! cnz delete$10 chk$pwe3: ; Restore info pop h! shld info! ret cmp$pw: ; Compare passwords inx h! mov b,m mov a,b! ora a! jnz cmp$pw2 mov d,h! mov e,l! inx h! inx h mvi c,9 cmp$pw1: inx h! mov a,m! dcr c! rz ora a! jz cmp$pw1 cpi 20h! jz cmp$pw1 xchg cmp$pw2: lxi d,(23-ubytes)! dad d! xchg lhld xdmaad! mvi c,8 cmp$pw3: ldax d! xra b! cmp m! jnz cmp$pw4 dcx d! inx h! dcr c! jnz cmp$pw3 ret cmp$pw4: dcx d! dcr c! jnz cmp$pw4 inx d if MPM call get$df$pwa! inr a! jnz cmp$pw5 inr a! ret cmp$pw5: else lxi h,df$password endif mvi c,8! jmp compare if MPM get$df$pwa: ; a = ff => no df pwa call rlr! lxi b,console! dad b mov a,m! cpi 16! mvi a,0ffh! rnc mov a,m! add a! add a! add a mvi h,0! mov l,a! lxi b,dfpassword! dad b ret endif set$pw: ; Set password in xfcb push h ; Save .xfcb(ex) lxi b,8 ; b = 0, c = 8 lxi d,(23-extnum)! dad d xchg! lhld xdmaad set$pw0: xra a! push a set$pw1: mov a,m! stax d! ora a! jz set$pw2 cpi 20h! jz set$pw2 inx sp! inx sp! push a set$pw2: add b! mov b,a dcx d! inx h! dcr c! jnz set$pw1 pop a! ora b! pop h! jnz set$pw3 ; is fx = 100 (directory label)? lda fx! cpi 100! jz set$pw3 ; yes mvi m,0 ; zero xfcb(ex) - no password set$pw3: inx d! mvi c,8 set$pw4: ldax d! xra b! stax d! inx d! dcr c! jnz set$pw4 inx h! ret get$xfcb: lhld info! mov a,m! push a ori 010h! mov m,a call search$extnum! mvi a,0! sta lret lhld info! pop b! mov m,b! rz get$xfcb1: call getdptra! xchg lxi h,extnum! dad d! mov a,m! ani 0e0h! ori 1 ret adjust$dmaad: push h! lhld xdmaad! dad d shld xdmaad! pop h! ret init$xfcb: call setcdr ; may have extended the directory lxi b,1014h ; b=10h, c=20 init$xfcb0: ; b = fcb(0) logical or mask ; c = zero count push b call getdptra! xchg! lhld info! xchg ; Zero extnum and modnum ldax d! ora b! mov m,a! inx d! inx h mvi c,11! call move! pop b! inr c init$xfcb1: dcr c! rz mvi m,0! inx h! jmp init$xfcb1 chk$xfcb$password: call get$xfcb1 chk$xfcb$password1: push h! call cmp$pw! pop h! ret endif stamp1: mvi c,0! jmp stamp3 stamp2: mvi c,4 stamp3: call get$dtba! ora a! rnz lxi d,seek$copy! push d stamp4: if MPM push h call get$stamp$add! xchg pop h else lxi d,stamp endif push h! push d mvi c,0! call timef ; does not modify hl,de mvi c,4! call compare mvi c,4! pop d! pop h! jnz move pop h! ret stamp5: call getdptra! dad b! lxi d,func$ret! push d jmp stamp4 if BANKED get$dtba$8: mvi c,8 endif get$dtba: ; c = offset of sfcb subfield (0,4,8) ; Return with a = 0 if sfcb exists ; Does fcb occupy 4th item of sector? lda dcnt! ani 3! cpi 3! rz ; yes mov b,a lhld buffa! lxi d,96! dad d ; Does sfcb reside in 4th directory item? mov a,m! sui 21h! rnz ; no ; hl = hl + 10*lret + 1 + c mov a,b! add a! mov e,a! add a! add a! add e inr a! add c! mov e,a! dad d! xra a ret qstamp: ; Is fcb 1st logical fcb for file? call qdirfcb1! rnz ; no qstamp1: ; Does directory label specify requested stamp? lhld drvlbla! mov a,c! ana m! jnz nowrite ; yes - verify drive r/w inr a! ret ; no - return with Z flag reset qdirfcb1: ; Routine to determine if fcb is 1st directory fcb ; for file ; Is fcb(ext) & ~extmsk & 00011111b = 0? lda extmsk! ori 1110$0000b! cma! mov b,a call getexta! mov a,m! ana b! rnz ; no ; is fcb(mod) & 0011$1111B = 0? inx h! inx h! mov a,m! ani 3fh! ret ; Z flag set if zero update$stamp: ; Is update stamping requested on drive? mvi c,0010$0000b! call qstamp1! rnz ; no ; Has file been written to since it was opened? call getmodnum! ani 40h! rnz ; yes - update stamp performed ; Search for 1st dir fcb call getexta! mov b,m! mvi m,0! push h inx h! inx h! mov c,m! mvi m,0! push b ; Search from beginning of directory call search$namlen ; Perform update stamp if dir fcb 1 found cnz stamp2 xra a! sta lret ; Restore fcb extent and module fields pop b! pop h! mov m,b! inx h! inx h! mov m,c! ret if MPM pack$sdcnt: ;packed$dcnt = dblk(low 15 bits) || dcnt(low 9 bits) ; if sdblk = 0 then dblk = shr(sdcnt,blkshf+2) ; else dblk = sdblk ; dcnt = sdcnt & (blkmsk || '11'b) ; ; packed$dcnt format (24 bits) ; ; 12345678 12345678 12345678 ; 23456789 .......1 ........ sdcnt (low 9 bits) ; ........ 9abcdef. 12345678 sdblk (low 15 bits) ; lhld sdblk! mov a,h! ora l! jnz pack$sdcnt1 lda blkshf! adi 2! mov c,a! lhld sdcnt call hlrotr pack$sdcnt1: dad h! xchg! lxi h,sdcnt! mvi b,1 lda blkmsk! ral! ora b! ral! ora b ana m! sta packed$dcnt lda blkshf! cpi 7! jnz pack$sdcnt2 inx h! mov a,m! ana b! jz pack$sdcnt2 mov a,e! ora b! mov e,a pack$sdcnt2: xchg! shld packed$dcnt+1 ret ; olist element = link(2) || atts(1) || dcnt(3) || ; pdaddr(2) || opncnt(2) ; ; link = 0 -> end of list ; ; atts - 80 - open in locked mode ; 40 - open in unlocked mode ; 20 - open in read/only mode ; 10 - deleted item ; 0n - drive code (0-f) ; ; dcnt = packed sdcnt+sdblk ; pdaddr = process descriptor addr ; opncnt = # of open calls - # of close calls ; olist item freed by close when opncnt = 0 ; ; llist element = link(2) || drive(1) || arecord(3) || ; pdaddr(2) || .olist$item(2) ; ; link = 0 -> end of list ; ; drive - 0n - drive code (0-f) ; ; arecord = record number of locked record ; pdaddr = process descriptor addr ; .olist$item = address of file's olist item search$olist: lxi h,open$root! jmp srch$list0 search$llist: lxi h,lock$root! jmp srch$list0 searchn$list: lhld cur$pos srch$list0: shld prv$pos ; search$olist, search$llist, searchn$list conventions ; ; b = 0 -> return next item ; b = 1 -> search for matching drive ; b = 3 -> search for matching dcnt ; b = 5 -> search for matching dcnt + pdaddr ; if found then z flag is set ; prv$pos -> previous list element ; cur$pos -> found list element ; hl -> found list element ; else prv$pos -> list element to insert after ; ; olist and llist are maintained in drive order srch$list1: mov e,m! inx h! mov d,m! xchg mov a,l! ora h! jz srch$list3 xra a! cmp b! jz srch$list6 inx h! inx h! lxi d,curdsk! mov a,m! ani 0fh! mov c,a ldax d! sub c! jnz srch$list4 mov a,b! dcr a! jz srch$list5 mov c,b! push h inx d! inx h! call compare pop h! jz srch$list5 srch$list2: dcx h! dcx h shld prv$pos! jmp srch$list1 srch$list3: inr a! ret srch$list4: jnc srch$list2 srch$list5: dcx h! dcx h srch$list6: shld cur$pos! ret delete$item: ; hl -> item to be deleted di push d! push h mov e,m! inx h! mov d,m lhld prv$pos! shld cur$pos ; prv$pos.link = delete$item.link mov m,e! inx h! mov m,d lhld free$root! xchg ; free$root = .delete$item pop h! shld free$root ; delete$item.link = previous free$root mov m,e! inx h! mov m,d pop d! ei! ret create$item: ; hl -> new item if successful ; z flag set if no free items lhld free$root! mov a,l! ora h! rz push d! push h! shld cur$pos mov e,m! inx h! mov d,m ; free$root = free$root.link xchg! shld free$root lhld prv$pos mov e,m! inx h! mov d,m pop h ; create$item.link = prv$pos.link mov m,e! inx h! mov m,d! dcx h xchg! lhld prv$pos ; prv$pos.link = .create$item mov m,e! inx h! mov m,d! xchg pop d! ret set$olist$item: ; a = attributes ; hl = olist entry address inx h! inx h mov b,a! lxi d,curdsk! ldax d! ora b mov m,a! inx h! inx d mvi c,5! call move xra a! mov m,a! inx h! mov m,a! ret set$sdcnt: mvi a,0ffh! sta sdcnt+1! ret tst$olist: mvi a,0c9h! sta chk$olist05! jmp chk$olist0 chk$olist: xra a! sta chk$olist05 chk$olist0: lxi d,dcnt! lxi h,sdcnt! mvi c,4! call move call pack$sdcnt! mvi b,3! call search$olist! rnz pop d ; pop return address inx h! inx h mov a,m! ani 80h! jz openx06 dcx h! dcx h push d! push h call compare$pds! pop h! pop d! jnz openx06 push d ; Restore return address chk$olist05: nop ; tst$olist changes this instr to ret call delete$item! lda pdcnt chk$olist1: adi 16! jz chk$olist1 sta pdcnt push a! call rlr lxi b,pdcnt$off! dad b! pop a mov m,a! ret remove$files: ; bc = pdaddr lhld cur$pos! push h lhld prv$pos! push h mov d,b! mov e,c! lxi h,open$root! shld cur$pos remove$file1: mvi b,0! push d! call searchn$list! pop d! jnz remove$file2 lxi b,6! call tst$tbl$lmt! jnz remove$file1 inx h! inx h! mov a,m! ori 10h! mov m,a sta deleted$files jmp remove$file1 remove$file2: pop h! shld prv$pos pop h! shld cur$pos ret delete$files: lxi h,open$root! shld cur$pos delete$file1: mvi b,0! call search$nlist! rnz inx h! inx h! mov a,m! ani 10h! jz delete$file1 dcx h! dcx h! call remove$locks! call delete$item jmp delete$file1 flush$files: lxi h,flushed! mov a,m! ora a! rnz inr m flush$file0: lxi h,open$root! shld cur$pos flush$file1: mvi b,1! call searchn$list! rnz push h! call remove$locks! call delete$item! pop h lxi d,6! dad d! mov e,m! inx h! mov d,m lxi h,pdcnt$off! dad d! mov a,m! ani 1! jnz flush$file1 mov a,m! ori 1! mov m,a lhld pdaddr! mvi c,2! call compare! jnz flush$file1 lda pdcnt! adi 10h! sta pdcnt! jmp flush$file1 free$files: ; free$mode = 1 - remove curdsk files for process ; 0 - remove all files for process lhld pdaddr! xchg! lxi h,open$root! shld curpos free$files1: lda free$mode! mov b,a push d! call searchn$list! pop d! rnz lxi b,6! call tst$tbl$lmt! jnz free$files1 push h! inx h! inx h! inx h call test$ffff! jnz free$files2 call test$ffff! jz free$files3 free$files2: mvi a,0ffh! sta incr$pdcnt free$files3: pop h! call remove$locks! call delete$item jmp free$files1 remove$locks: shld file$id inx h! inx h! mov a,m! ani 40h! jz remove$lock3 push d! lhld prv$pos! push h lhld file$id! xchg! lxi h,lock$root! shld cur$pos remove$lock1: mvi b,0! push d! call searchn$list! pop d jnz remove$lock2 lxi b,8! call tst$tbl$lmt! jnz remove$lock1 call delete$item jmp remove$lock1 remove$lock2: pop h! shld prv$pos! pop d remove$lock3: lhld file$id! ret tst$tbl$lmt: push h! dad b mov a,m! inx h! mov h,m sub e! jnz tst$tbl$lmt1 mov a,h! sub d tst$tbl$lmt1: pop h! ret create$olist$item: mvi b,1! call search$olist di call create$item! lda attributes! call set$olist$item ei ret count$opens: xra a! sta open$cnt lhld pdaddr! xchg! lxi h,open$root! shld curpos count$open1: mvi b,0! push d! call searchn$list! pop d! jnz count$open2 lxi b,6! call tst$tbl$lmt! jnz count$open1 lda open$cnt! inr a! sta open$cnt jmp count$open1 count$open2: lxi h,open$max! lda open$cnt! ret count$locks: xra a! sta lock$cnt xchg! lxi h,lock$root! shld cur$pos count$lock1: mvi b,0! push d! call searchn$list! pop d! rnz lxi b,8! call tst$tbl$lmt! jnz count$lock1 lda lock$cnt! inr a! sta lock$cnt jmp count$lock1 check$free: lda mult$cnt! mov e,a mvi d,0! lxi h,free$root! shld cur$pos check$free1: mvi b,0! push d! call searchn$list! pop d! jnz check$free2 inr d! mov a,d! sub e! jc check$free1 ret check$free2: pop h! mvi a,14! jmp sta$ret lock: ; record lock and unlock call reselect! call check$fcb call test$unlocked rz ; file not opened in unlocked mode lhld xdmaad! mov e,m! inx h! mov d,m xchg! inx h! inx h mov a,m! mov b,a! lda curdsk! sub b ani 0fh! jnz lock8 ; invalid file id mov a,b! ani 40h! jz lock8 ; invalid file id dcx h! dcx h! shld file$id lda lock$unlock! inr a! jnz lock1 ; jmp if unlock call count$locks lda lock$cnt! mov b,a lda mult$cnt! add b! mov b,a lda lock$max! cmp b mvi a,12! jc sta$ret ; too many locks by this process call check$free lock1: call save$rr! lxi h,lock9! push h! lda mult$cnt lock2: push a! call get$lock$add lda lock$unlock! inr a! jnz lock3 call test$lock lock3: pop a! dcr a! jz lock4 call incr$rr! jmp lock2 lock4: call reset$rr! lda mult$cnt lock5: push a! call get$lock$add lda lock$unlock! inr a! jnz lock6 call set$lock! jmp lock7 lock6: call free$lock lock7: pop a! dcr a! rz call incr$rr! jmp lock5 lock8: mvi a,13! jmp sta$ret ; invalid file id lock9: call reset$rr! ret get$lock$add: lxi h,0! dad sp! shld lock$sp mvi a,0ffh! sta lock$shell call rseek xra a! sta lock$shell call getfcb lhld aret! mov a,l! ora a! jnz lock$err call index! lxi h,1! jz lock$err call atran! ret lock$perr: xra a! sta lock$shell xchg! lhld lock$sp! sphl! xchg lock$err: pop d ; Discard return address pop b ; b = mult$cnt-# recs processed lda mult$cnt! sub b add a! add a! add a! add a ora h! mov h,a! mov b,a shld aret! ret test$lock: call move$arecord mvi b,3! call search$llist! rnz call compare$pds! rz lxi h,8! jmp lock$err set$lock: call move$arecord mvi b,1! call search$llist di call create$item xra a! call set$olist$item xchg! lhld file$id! xchg mov m,d! dcx h! mov m,e ei! ret free$lock: call move$arecord mvi b,5! call search$llist! rnz free$lock0: call delete$item mvi b,5! call searchn$list! rnz jmp free$lock0 compare$pds: lxi d,6! dad d! xchg lxi h,pdaddr! mvi c,2! jmp compare move$arecord: lxi d,arecord! lxi h,packed$dcnt fix$olist$item: lxi d,xdcnt! lxi h,sdcnt ; Is xdblk,xdcnt < sdblk,sdcnt mvi c,4! ora a! fix$ol1: ldax d! sbb m! inx h! inx d! dcr c! jnz fix$ol1 rnc ; yes - update olist entry call swap! call sdcnt$eq$xdcnt lxi h,open$root! shld cur$pos ; Find file's olist entry fix$ol2: call swap! call pack$sdcnt! call swap mvi b,3! call searchn$list! rnz ; Update olist entry with new dcnt value push h! call pack$sdcnt! pop h inx h! inx h! inx h! lxi d,packed$dcnt mvi c,3! call move! jmp fix$ol2 hl$eq$hl$and$de: mov a,l! ana e! mov l,a mov a,h! ana d! mov h,a ret remove$drive: xchg! lda curdsk! mov c,a! lxi h,1 call hlrotl mov a,l! cma! ana e! mov e,a mov a,h! cma! ana d! mov d,a xchg! ret diskreset: lxi h,0! shld ntlog xra a! sta set$ro$flag lhld info intrnldiskreset: xchg! lhld open$root! mov a,h! ora l! rz xchg! lda curdsk! push a! mvi b,0 dskrst1: mov a,l! rar! jc dskrst3 dskrst2: mvi c,1! call hlrotr! inr b mov a,h! ora l! jnz dskrst1 pop a! sta curdsk lhld ntlog! xchg! lhld tlog mov a,l! ora e! mov l,a mov a,h! ora d! mov h,a! shld tlog inr a! ret dskrst3: push b! push h! mov a,b! sta curdsk lhld rlog! call test$vector1! push a lhld rodsk! lda curdsk! call test$vector1! mov b,a pop h! lda set$ro$flag! ora b! ora h! sta check$disk lxi h,open$root! shld cur$pos dskrst4: mvi b,1! call searchn$list! jnz dskrst6 lda check$disk! ora a! jz dskrst5 push h! call compare$pds! jz dskrst45 pop h! xra a! xchg! jmp dskrst6 dskrst45: lxi d,ntlog! call set$cdisk pop h! jmp dskrst4 dskrst5: lhld info! call remove$drive! shld info ori 1 dskrst6: pop h! pop b! jnz dskrst2 ; error - olist item exists for another process ; for removable drive to be reset pop a! sta curdsk! mov a,b! adi 41h ; a = ascii drive lxi h,6! dad d! mov c,m! inx h! mov b,m ; bc = pdaddr push psw! call test$error$mode! pop d! jnz dskrst7 mov a,d push b! push psw call rlr! lxi d,console! dad d! mov d,m ; d = console # lxi b,deniedmsg! call xprint pop psw! mov c,a! call conoutx mvi c,':'! call conoutx lxi b,cnsmsg! call xprint pop h! push h! lxi b,console! dad b mov a,m! adi '0'! mov c,a! call conoutx lxi b,progmsg! call xprint pop h! call dsplynm dskrst7: pop h ; Remove return addr from diskreset lxi h,0ffffh! shld aret ; Flag the error ret deniedmsg: db cr,lf,'disk reset denied, drive ',0 cnsmsg: db ' console ',0 progmsg: db ' program ',0 endif ; ; individual function handlers ; func12: ; Return version number if MPM lxi h,0100h+dvers! jmp sthl$ret else lda version! jmp sta$ret ; lret = dvers (high = 00) endif func13: if MPM lhld dlog! shld info call diskreset! jz reset$all call reset$37 jmp func13$cont reset$all: ; Reset disk system - initialize to disk 0 lxi h,0! shld rodsk! shld dlog shld rlog! shld tlog func13$cont: mvi a,0ffh! sta curdsk else lxi h,0ffffh! call reset$37x endif xra a! sta olddsk ; Note that usrcode remains unchanged if MPM xra a! call getmemseg ; a = mem seg tbl index ora a! rz inr a! rz call rlradr! lxi b,msegtbl-rlros! dad b add a! add a! mov e,a! mvi d,0! dad d mov h,m! mvi l,80h jmp intrnlsetdma else lxi h,tbuff! shld dmaad ; dmaad = tbuff jmp setdata ; to data dma address endif func14: if MPM call tmpselect ; seldsk = reg e call rlr! lxi b,diskselect! dad b mov a,m! ani 0fh! rrc! rrc! rrc! rrc mov b,a! lda seldsk! ora b! rrc! rrc! rrc! rrc mov m,a! ret else call tmpselect ; seldsk = reg e lda seldsk! sta olddsk! ret endif func15: ; Open file call clrmodnum ; Clear the module number if MPM call reselect xra a! sta make$flag call set$sdcnt lxi h,open$file! push h mvi a,0c9h! sta check$fcb4 call check$fcb1 pop h! lda high$ext! cpi 060h! jnz open$file call home! call set$end$dir jmp open$user$zero open$file: call set$sdcnt call reset$chksum$fcb ; Set invalid check sum else call reselectx endif call check$wild ; Check for wild chars in fcb if MPM call get$atts! ani 1100$0000b ; a = attributes cpi 1100$0000b! jnz att$ok ani 0100$0000b ; Mask off unlock mode att$ok: sta high$ext mov b,a! ora a! rar! jnz att$set mvi a,80h att$set: sta attributes! mov a,b ani 80h! jnz call$open endif lda usrcode! ora a! jz call$open mvi a,0feh! sta xdcnt+1! inr a! sta search$user0 if MPM sta sdcnt0+1 endif call$open: call open! call openx ; returns if unsuccessful, a = 0 lxi h,search$user0! cmp m! rz mov m,a! lda xdcnt+1! cpi 0feh! rz ; ; file exists under user 0 ; if MPM call swap endif call set$dcnt$dblk if MPM mvi a,0110$0000b else mvi a,80h endif sta high$ext open$user$zero: ; Set fcb user # to zero lhld info! mvi m,0 mvi c,namlen! call searchi! call searchn call open1 ; Attempt reopen under user zero call openx ; openx returns only if unsuccessful ret openx: call end$of$dir! rz call getfcba! mov a,m! inr a! jnz openxa dcx d! dcx d! ldax d! mov m,a openxa: ; open successful pop h ; Discard return address ; Was file opened under user 0 after unsuccessful ; attempt to open under user n? if MPM lda high$ext! cpi 060h! jz openx00 ; yes ; Was file opened in locked mode? ora a! jnz openx0 ; no ; does user = zero? lhld info! ora m! jnz openx0 ; no ; Does file have read/only attribute set? call rotest! jnc openx0 ; no ; Does file have system attribute set? inx h! mov a,m! ral! jnc openx0 ; no ; Force open mode to read/only mode and set user 0 flag ; if file opened in locked mode, user = 0, and ; file has read/only and system attributes set openx00: else lda high$ext! ral! jnc openx0 endif ; Is file under user 0 a system file ? if MPM mvi a,20h! sta attributes endif lhld info! lxi d,10! dad d mov a,m! ani 80h! jnz openx0 ; yes - open successful ; open fails sta high$ext! jmp lret$eq$ff openx0: if MPM call reset$chksum$fcb else call set$lsn endif if BANKED ; Are passwords enabled on drive? call get$dir$mode! ani 80h! jz openx1a ; no ; Is this 1st dir fcb? call qdirfcb1! jnz openx0a ; no ; Does sfcb exist? call get$dtba$8! ora a! jnz openx0a ; no ; Is sfcb password mode read or write? mov a,m! ani 0c0h! jz openx1a ; no ; Does xfcb exist? call xdcnt$eq$dcnt call get$xfcb! jnz openx0b ; yes ; no - set sfcb password mode to zero call restore$dir$fcb! rz ; (error) ; Does sfcb still exist? call get$dtba$8! ora a! jnz openx1a ; no (error) ; sfcb password mode = 0 mov m,a ; update sfcb call nowrite! cz seek$copy jmp openx1a openx0a: call xdcnt$eq$dcnt ; Does xfcb exist? call get$xfcb! jz openx1 ; no openx0b: ; yes - check password call cmp$pw! jz openx1 call chk$pw$error lda pw$mode! ani 0c0h! jz openx1 ani 80h! jnz pw$error mvi a,080h! sta xfcb$read$only openx1: call restore$dir$fcb! rz ; (error) openx1a: call set$lsn if MPM call pack$sdcnt ; Is this file currently open? mvi b,3! call search$olist! jz openx04 openx01: ; no - is olist full? lhld free$root! mov a,l! ora h! jnz openx03 ; yes - error openx02: mvi a,11! jmp set$aret openx03: ; Has process exceeded open file maximum? call count$opens! sub m! jc openx035 ; yes - error openx034: mvi a,10! jmp set$aret openx035: ; Create new olist element call create$olist$item jmp openx08 openx04: ; Do file attributes match? inx h! inx h lda attributes! ora m! cmp m! jnz openx06 ; yes - is open mode locked? ani 80h! jnz openx07 ; no - has this file been opened by this process? lhld prv$pos! shld cur$pos mvi b,5! call searchn$list! jnz openx01 openx05: ; yes - increment open file count lxi d,8! dad d! inr m! jnz openx08 ; count overflow inx h! inr m! jmp openx08 openx06: ; error - file opened by another process in imcompatible mode mvi a,5! jmp set$aret openx07: ; Does this olist item belong to this process? dcx h! dcx h! push h call compare$pds pop h! jnz openx06 ; no - error jmp openx05 ; yes openx08:; Wopen ok ; Was file opened in unlocked mode? lda attributes! ani 40h! jz openx09 ; no ; yes - return .olist$item in ranrec field of fcb call get$rra lxi d,cur$pos! mvi c,2! call move openx09: call set$fcb$cks$flag lda make$flag! ora a! rnz endif endif mvi c,0100$0000b openx2: call qstamp! cz stamp1 lxi d,olog! jmp set$cdisk func16: ; Close file call reselect if MPM call get$atts! sta attributes lxi h,close00! push h mvi a,0c9h! sta check$fcb4 call check$fcb1! pop h call set$sdcnt call getmodnum! ani 80h! jnz close01 call close! jmp close02 close00: mvi a,6! jmp set$aret close01: mvi a,0ffh! sta dont$close! call close1 close02: else call set$lsn call chek$fcb! call close endif lda lret! inr a! rz jmp flush ; Flush buffers if MPM lda attributes! ral! rc call pack$sdcnt ; Find olist item for this process & file mvi b,5! call search$olist! jnz close03 ; Decrement open count push h! lxi d,8! dad d mov a,m! sui 1! mov m,a! inx h mov a,m! sbi 0! mov m,a! dcx h ; Is open count = 0ffffh call test$ffff! pop h! jnz close03 ; yes - remove file's olist entry shld file$id! call delete$item call reset$chksum$fcb ; if unlocked file, remove file's locktbl entries call test$unlocked! jz close03 lhld file$id! call remove$locks close03: ret endif func17: ; Search for first occurrence of a file xchg! xra a csearch: push a mov a,m! cpi '?'! jnz csearch1 ; no reselect if ? call curselect! call noselect0! mvi c,0! jmp csearch3 csearch1: call getexta! mov a,m! cpi '?'! jz csearch2 call clr$ext! call clrmodnum csearch2: call reselectx mvi c,namlen csearch3: pop a! push a! jz csearch4 ; dcnt = dcnt & 0fch lhld dcnt! push h! mvi a,0fch ana l! mov l,a! shld dcnt call rd$dir pop h! shld dcnt csearch4: pop a lxi h,dir$to$user push h jz search lda searchl! mov c,a! call searchi! jmp searchn func18: ; Search for next occurrence of a file name if BANKED xchg! shld searcha else lhld searcha! shld info endif ori 1! jmp csearch func19: ; Delete a file call reselectx jmp delete func20: ; Read a file call reselect call check$fcb jmp seqdiskread func21: ; Write a file call reselect call check$fcb jmp seqdiskwrite func22: ; Make a file if BANKED call get$atts! sta attributes endif call clr$ext call clrmodnum ; fcb mod = 0 call reselectx if MPM call reset$chksum$fcb endif call check$wild call set$xdcnt ; Reset xdcnt for make if MPM call set$sdcnt endif call open ; Verify file does not already exist if MPM call reset$chksum$fcb endif ; Does dir fcb for fcb exist? ; ora a required to reset carry call end$of$dir! ora a! jz makea0 ; no ; Is dir$ext < fcb(ext)? call get$dir$ext! cmp m! jnc file$exists ; no makea0: push a ; carry set if dir fcb already exists if MPM lda attributes! ani 80h! rrc! jnz makex00 mvi a,80h makex00: sta make$flag lda sdcnt+1! inr a! jz makex01 call pack$sdcnt mvi b,3! call search$olist! jz make$x02 makex01: lhld free$root! mov a,l! ora h! jz openx02 jmp makex03 makex02: inx h! inx h lda makeflag! ana m! jz openx06 dcx h! dcx h! call compare$pds! jz makex03 lda makeflag! ral! jc openx06 makex03: endif if BANKED ; Is fcb 1st fcb for file? call qdirfcb1! jz makex04 ; yes ; no - does dir lbl require passwords? call get$dir$mode! ani 80h! jz makex04 ; no - does xfcb exist with mode 1 or 2 password? call get$xfcb! jz makex04 ; yes - check password call chk$xfcb$password1! jz makex04 ; Verify password error call chk$pw$error lda pw$mode! ani 0c0h! jnz pw$error makex04: endif ; carry on stack indicates a make not required because ; of extent folding pop a! cnc make if MPM call reset$chksum$fcb endif ; end$of$dir call either applies to above make or open call call end$of$dir! rz ; Return if make unsuccessful if not MPM call set$lsn endif if BANKED ; Are passwords activated by dir lbl? call get$dir$mode! ani 80h! jz make3a ; Did user set password attribute? lda attributes! ani 40h! jz make3a ; Is fcb file's 1st logical fcb? call qdirfcb1! jnz make3a ; yes - does xfcb already exist for file call xdcnt$eq$dcnt call get$xfcb! jnz make00 ; yes ; Attempt to make xfcb mvi a,0ffh! sta make$xfcb! call make! jnz make00 ; xfcb make failed - delete fcb that was created above call search$namlen call delete10! jmp lret$eq$ff ; Return with a = 0ffh make00: call init$xfcb ; Initialize xfcb ; Get password mode from dma + 8 xchg! lhld xdmaad! lxi b,8! dad b! xchg ldax d! ani 0e0h! jnz make2 mvi a,080h ; default password mode is read protect make2: sta pw$mode ; Set xfcb password mode field push a! call getxfcb1! pop a! mov m,a ; Set xfcb password and password checksum ; Fix hash table and write xfcb call set$pw! mov m,b! call sdl3 ; Return to fcb call restore$dir$fcb! rz ; Does sfcb exist? mvi c,8! call getdtba! ora a! jnz make3a ; no ; Place password mode in sfcb if sfcb exists lda pw$mode! mov m,a! call seek$copy call set$lsn endif make3a: mvi c,0101$0000b if MPM call openx2 lda make$flag! sta attributes ani 40h! ral! sta high$ext lda sdcnt+1! inr a! jnz makexx02 call sdcnt$eq$xdcnt! call pack$sdcnt jmp openx03 makexx02: call fix$olist$item! jmp openx1 jmp set$fcb$cks$flag else call openx2 mvi c,0010$0000b! call qstamp! rnz call stamp2! jmp set$filewf endif file$exists: mvi a,8 set$aret: mov c,a! sta aret+1! call lret$eq$ff if MPM call test$error$mode! jnz goback else jmp goerr1 endif if MPM mov a,c! sui 3 mov l,a! mvi h,0! dad h lxi d,xerr$list! dad d mov e,m! inx h! mov d,m xchg! jmp report$err endif func23: ; Rename a file call reselectx jmp rename func24: ; Return the login vector lhld dlog! jmp sthl$ret func25: ; Return selected disk number lda seldsk! jmp sta$ret func26: if MPM ; Save dma address in process descriptor lhld info intrnlsetdma: xchg call rlr! lxi b,disksetdma! dad b mov m,e! inx h! mov m,d endif ; Set the subsequent dma address to info xchg! shld dmaad ; dmaad = info jmp setdata ; to data dma address func27: ; Return the login vector address call curselect lhld alloca! jmp sthl$ret if MPM func28: ; Write protect current disk ; first check for open files on disk mvi a,0ffh! sta set$ro$flag lda seldsk! mov c,a! lxi h,0001h call hlrotl! call intrnldiskreset jmp set$ro else func28: equ set$ro ; Write protect current disk endif func29: ; Return r/o bit vector lhld rodsk! jmp sthl$ret func30: ; Set file indicators call check$wild call reselectx call indicators jmp copy$dirloc ; lret=dirloc func31: ; Return address of disk parameter block call curselect lhld dpbaddr sthl$ret: shld aret! ret func32: ; Set user code lda linfo! cpi 0ffh! jnz setusrcode ; Interrogate user code instead lda usrcode! jmp sta$ret ; lret=usrcode setusrcode: ani 0fh! sta usrcode if MPM push a call rlr! lxi b,diskselect! dad b pop b mov a,m! ani 0f0h! ora b! mov m,a endif ret func33: ; Random disk read operation call reselect call check$fcb jmp randiskread ; to perform the disk read func34: ; Random disk write operation call reselect call check$fcb jmp randiskwrite ; to perform the disk write func35: ; Return file size (0-262,144) call reselect jmp getfilesize func36 equ setrandom ; Set random record func37: ; Drive reset if MPM call diskreset reset$37: lhld info else xchg endif reset$37x: mov a,l! cma! mov e,a! mov a,h! cma lhld dlog! ana h! mov d,a! mov a,l! ana e mov e,a! lhld rodsk! xchg! shld dlog if MPM push h! call hl$eq$hl$and$de else mov a,l! ana e! mov l,a mov a,h! ana d! mov h,a endif shld rodsk if MPM pop h! xchg! lhld rlog! call hl$eq$hl$and$de! shld rlog endif ; Force select call in next curselect mvi a,0ffh! sta curdsk! ret if MPM func38: ; Access drive lxi h,packed$dcnt! mvi a,0ffh mov m,a! inx h! mov m,a! inx h! mov m,a xra a! xchg! lxi b,16 acc$drv0: dad h! adc b! dcr c! jnz acc$drv0 ora a! rz sta mult$cnt! dcr a! push a call acc$drv02 pop a! jmp openx02 ; insufficient free lock list items acc$drv02: call check$free! pop h ; Discard return addr, free space exists call count$opens! pop b! add b! jc openx034 sub m! jnc openx034 ; openmax exceeded lhld info! lda curdsk! push a! mvi a,16 acc$drv1: dcr a! dad h! jc acc$drv2 acc$drv15: ora a! jnz acc$drv1 pop a! sta curdsk! ret acc$drv2: push a! push h! sta curdsk call create$olist$item pop h! pop a! jmp acc$drv15 func39: ; Free drive lhld open$root! mov a,h! ora l! rz xra a! sta incr$pdcnt! inr a! sta free$mode lhld info! mov a,h! cmp l! jnz free$drv1 inr a! jnz free$drv1 sta free$mode! call free$files! jmp free$drv3 free$drv1: lda curdsk! push a! mvi a,16 free$drv2: dcr a! dad h! jc free$drv4 free$drv25: ora a! jnz free$drv2 pop a! sta curdsk free$drv3: lda incr$pdcnt! ora a! rz lda pdcnt! jmp chk$olist1 free$drv4: push a! push h! sta curdsk call free$files pop h! pop a! jmp free$drv25 else func38 equ func$ret func39 equ func$ret endif func40 equ func34 ; Write random with zero fill if MPM func41 equ func$ret ; Test & write func42: ; Record lock mvi a,0ffh! sta lock$unlock! jmp lock func43: ; Record unlock xra a! sta lock$unlock! jmp lock else func42 equ func$ret ; Record lock func43 equ func$ret ; Record unlock endif func44: ; Set multi-sector count mov a,e! ora a! jz lret$eq$ff cpi 129! jnc lret$eq$ff sta mult$cnt if MPM mov d,a call rlr! lxi b,mult$cnt$off! dad b mov m,d endif ret func45: ; Set bdos error mode if MPM call rlr! lxi b,pname+4! dad b call set$pflag mov m,a! inx h call set$pflag mov m,a! ret set$pflag: mov a,m! ani 7fh! inr e! rnz ori 80h! ret else mov a,e! sta error$mode endif ret func46: ; Get free space ; Perform temporary select of specified drive call tmpselect lhld alloca! xchg ; de = alloc vector addr call get$nalbs ; Get # alloc blocks ; hl = # of allocation vector bytes ; Count # of true bits in allocation vector lxi b,0 ; bc = true bit accumulator gsp1: ldax d gsp2: ora a! jz gsp4 gsp3: rar! jnc gsp3 inx b! jmp gsp2 gsp4: inx d! dcx h mov a,l! ora h! jnz gsp1 ; hl = 0 when allocation vector processed ; Compute maxall + 1 - bc lhld maxall! inx h mov a,l! sub c! mov l,a mov a,h! sbb b! mov h,a ; hl = # of available blocks on drive lda blkshf! mov c,a! xra a call shl3bv ; ahl = # of available sectors on drive ; Store ahl in beginning of current dma xchg! lhld xdmaad! mov m,e! inx h mov m,d! inx h! mov m,a! ret if MPM func47 equ func$ret else func47: ; Chain to program lxi h,ccp$flgs! mov a,m! ori 80h! mov m,a inr e! jnz rebootx1 mov a,m! ori 40h! mov m,a jmp rebootx1 endif func48: ; Flush buffers call check$all$media call flushf call diocomp flush0: ; Function 98 entry point lhld dlog! mvi a,16 flush1: dcr a! dad h! jnc flush5 push a! push h! mov e,a! call tmpselect ; seldsk = e lda fx! cpi 48! jz flush3 ; Function 98 - reset allocation ; Copy 2nd ALV over 1st ALV call copy$alv! jmp flush35 flush3: call flushx ; if e = 0ffh then discard buffers after possible flush lda linfo! inr a! jnz flush4 flush35: call discard$data flush4: pop h! pop a flush5: ora a! jnz flush1 ret flush: call flushf call diocomp flushx: lda phymsk! ora a! rz mvi a,4! jmp deblock$dta if MPM func49 equ func$ret else func49: ; Get/Set system control block xchg! mov a,m! cpi 99! rnc xchg! lxi h,scb! add l! mov l,a xchg! inx h! mov a,m! cpi 0feh! jnc func49$set xchg! mov e,m! inx h! mov d,m! xchg jmp sthl$ret func49$set: mov b,a! inx h! mov a,m! stax d! inr b! rz inx h! inx d! mov a,m! stax d! ret endif if MPM func50 equ func$ret else func50: ; Direct bios call ; de -> function (1 byte) ; a value (1 byte) ; bc value (2 bytes) ; de value (2 bytes) ; hl value (2 bytes) lxi h,func50$ret! push h xchg if BANKED mov a,m! cpi 27! rz cpi 12! jnz dir$bios1 lxi d,dir$bios3! push d dir$bios1: cpi 9! jnz dir$bios2 lxi d,dirbios4! push d dir$bios2: endif push h! inx h! inx h mov c,m! inx h! mov b,m! inx h mov e,m! inx h! mov d,m! inx h mov a,m! inx h! mov h,m! mov l,a xthl! mov a,m! push h! mov l,a! add a! add l lxi h,bios add l! mov l,a! xthl inx h! mov a,m! pop h! xthl! ret if BANKED dir$bios3: mvi a,1! jmp setbnkf dir$bios4: mov a,l! ora h! rz xchg! lxi h,10! dad d! mvi m,0 ; Zero login sequence # lhld common$base! call subdh! xchg! rnc ; Copy DPH to common memory xchg! lhld info! inx h! push h! lxi b,25 call movef! pop h! ret endif func50$ret: if BANKED shld aret! mov b,a lhld info! mov a,m cpi 9! rz cpi 16! rz cpi 20! rz cpi 22! rz mov a,b! jmp sta$ret else xchg! lhld entsp! sphl! xchg! ret endif endif func98 equ flush0 ; Reset Allocation func99: ; Truncate file call reselectx call check$wild if BANKED call chk$password! cnz chk$pw$error endif mvi c,true! call rseek! jnz lret$eq$ff ; compute dir$fcb size call getdptra! lxi d,reccnt call compute$rr ; cba = fcb size ; Is random rec # >= dir$fcb size call get$rra! call compare$rr jc lret$eq$ff ; yes ( > ) ora d! jz lret$eq$ff ; yes ( = ) ; Perform truncate call check$rodir ; may be r/o file call wrdir ; verify BIOS can write to disk call update$stamp ; Set update stamp call search$extnum trunc1: jz copy$dirloc ; is dirfcb < fcb? call compare$mod$ext! jc trunc2 ; yes ; remove dirfcb blocks from allocation vector push a! mvi c,0! call scandm$ab! pop a ; is dirfcb = fcb? jz trunc3 ; yes ; delete dirfcb call getdptra! mvi m,empty! call fix$hash trunc15: call wrdir trunc2: call searchn jmp trunc1 trunc3: call getfcb! call dm$position call zero$dm ; fcb(extnum) = dir$ext after blocks removed call get$dir$ext! cmp m! mov m,a! push a ; fcb(rc) = fcb(cr) + 1 call getfcba! mov a,m! inr a! stax d ; rc = 0 or 128 if dir$ext < fcb(extnum) pop a! xchg! cnz set$rc3 ; rc = 0 if no blocks remain in fcb lda dminx! ora a! cz set$rc3 lxi b,11! call get$fcb$adds! xchg ; reset archive (t3') attribute bit mov a,m! ani 7fh! mov m,a! inx h! inx d ; dirfcb(extnum) = fcb(extnum) ldax d! mov m,a ; advance to .fcb(reccnt) & .dirfcb(reccnt) inx h! mvi m,0! inx h! inx h inx d! inx d! inx d ; dirfcb_rc+dskmap = fcb_rc+dskmap mvi c,17! call move ; restore non-erased blkidxs in allocation vector mvi c,1! call scandm$ab jmp trunc15 get$fcb$adds: call getdptra! dad b! xchg lhld info! dad b! ret compare$mod$ext: lxi b,modnum! call get$fcb$adds mov a,m! ani 3fh! mov b,a ; compare dirfcb(modnum) to fcb(modnum) ldax d! cmp b! rnz ; dirfcb(modnum) ~= fcb(modnum) dcx h! dcx h! dcx d! dcx d ; compare dirfcb(extnum) to fcb(extnum) ldax d! mov c,m! call compext! rz ; dirfcb(extnum) = fcb(extnum) ldax d! cmp m! ret zero$dm: inr a! lxi h,single! inr m! jz zero$dm1 add a zero$dm1: dcr m call getdma! mov c,a! mvi b,0! dad b mvi a,16 zero$dm2: cmp c! rz mov m,b! inx h! inr c! jmp zero$dm2 if BANKED func100: ; Set directory label ; de -> .fcb ; drive location ; name & type fields user's discretion ; extent field definition ; bit 1 (80h): enable passwords on drive ; bit 2 (40h): enable file access ; bit 3 (20h): enable file update stamping ; bit 4 (10h): enable file create stamping ; bit 8 (01h): assign new password to dir lbl call reselectx lhld info! mvi m,21h! mvi c,1 call search! jnz sdl0 call getexta! mov a,m! ani 0111$0000b! jnz lret$eq$ff sdl0: ; Does dir lbl exist on drive? lhld info! mvi m,20h! mvi c,1 call set$xdcnt! call search! jnz sdl1 ; no - make one mvi a,0ffh! sta make$xfcb call make! rz ; no dir space call init$xfcb lxi b,24! call stamp5! call stamp1 sdl1: ; Update date & time stamp lxi b,28! call stamp5! call stamp2 ; Verify password - new dir lbl falls through call chk$xfcb$password! jnz pw$error lxi b,0! call init$xfcb0 ; Set dir lbl dta in extent field ldax d! ori 1h! mov m,a ; Low bit of dir lbl data set to indicate dir lbl exists ; Update drive's dir lbl vector element push h! lhld drvlbla! mov m,a! pop h sdl2: ; Assign new password to dir lbl or xfcb? ldax d! ani 1! jz sdl3 ; yes - new password field is in 2nd 8 bytes of dma lxi d,8! call adjust$dmaad call set$pw! mov m,b lxi d,-8! call adjust$dmaad sdl3: call fix$hash jmp seek$copy else func100 equ lret$eq$ff func103 equ lret$eq$ff endif func101: ; Return directory label data ; Perform temporary select of specified drive call tmpselect call get$dir$mode! jmp sta$ret func102: ; Read file xfcb call reselectx call check$wild call zero$ext$mod call search$namlen! rz call getdma! lxi b,8! call zero push h! mvi c,0! call get$dtba! ora a! jnz rxfcb2 pop d! xchg! mvi c,8 if BANKED call move! ldax d! jmp rxfcb3 else jmp move endif rxfcb2: pop h! lxi b,8 if BANKED call zero! call get$xfcb! rz mov a,m rxfcb3: call getexta! mov m,a! ret else jmp zero endif if BANKED func103: ; Write or update file xfcb call reselectx ; Are passwords enabled in directory label? call get$dir$mode! ral! jnc lret$eq$ff ; no call check$wild ; Save .fcb(ext) & ext call getexta! mov b,m! push h! push b ; Set extent & mod to zero call zero$ext$mod ; Does file's 1st fcb exist in directory? call search$namlen ; Restore extent pop b! pop h! mov m,b! rz ; no call set$xdcnt ; Does sfcb exist? call get$dtba$8! ora a! jz wxfcb5 ; yes ; No - Does xfcb exist? call get$xfcb! jnz wxfcb1 ; yes wxfcb0: ; no - does file exist in directory? mvi a,0ffh! sta make$xfcb call search$extnum! rz ; yes - attempt to make xfcb for file call make! rz ; no dir space ; Initialize xfcb call init$xfcb wxfcb1: ; Verify password - new xfcb falls through call chk$xfcb$password! jnz pw$error ; Set xfcb options data push h! call getexta! pop d! xchg mov a,m! ora a! jnz wxfcb2 ldax d! ani 1! jnz wxfcb2 call sdl3! jmp wxfcb4 wxfcb2: ldax d! ani 0e0h! jnz wxfcb3 mvi a,80h wxfcb3: mov m,a! call sdl2 wxfcb4: call get$xfcb1! dcr a! sta pw$mode call zero$ext$mod call search$namlen! rz call get$dtba$8! ora a! rnz lda pw$mode! mov m,a! jmp seek$copy wxfcb5: ; Take sfcb's password mode over xfcb's mode mov a,m! push a call get$xfcb ; does xfcb exist? pop b! jz wxfcb0 ; no ; Set xfcb's password mode to sfcb's mode mov m,b! jmp wxfcb1 endif func104: ; Set current date and time if MPM call get$stamp$add else lxi h,stamp endif call copy$stamp mvi m,0! mvi c,0ffh! jmp timef func105: ; Get current date and time if MPM call get$stamp$add else mvi c,0! call timef lxi h,stamp endif xchg call copy$stamp ldax d! jmp sta$ret copy$stamp: mvi c,4! jmp move ; ret if MPM get$stamp$add: call rlradr! lxi b,-5! dad b ret endif if BANKED func106: ; Set default password if MPM call get$df$pwa! inr a! rz lxi b,7! dad b else lxi h,df$password+7 endif xchg! lxi b,8! push h jmp set$pw0 else func106 equ func$ret endif func107: ; Return serial number if MPM lhld sysdat! mvi l,181 else lxi h,serial endif xchg! mvi c,6! jmp move func108: ; Get/Set program return code ; Is de = 0ffffh? mov a,d! ana e! inr a lhld clp$errcde! jz sthl$ret ; yes - return return code xchg! shld clp$errcde! ret ; no - set return code goback0: lxi h,0ffffh! shld aret goback: ; Arrive here at end of processing to return to user lda resel! ora a! jz retmon if MPM lda comp$fcb$cks! ora a! cnz set$chksum$fcb endif lhld info! lda fcbdsk! mov m,a ; fcb(0)=fcbdsk if BANKED ; fcb(7) = fcb(7) | xfcb$read$only lxi d,7! dad d! lda xfcb$read$only! ora m! mov m,a endif if MPM ; if high$ext = 60h then fcb(8) = fcb(8) | 80h ; else fcb(ext) = fcb(ext) | high$ext call getexta! lda high$ext! cpi 60h! jnz goback2 lxi d,-4! dad d! mvi a,80h goback2: ora m! mov m,a else ; fcb(8) = fcb(8) | high$ext if BANKED inx h else lxi d,8! dad d endif lda high$ext! ora m! mov m,a endif ; return from the disk monitor retmon: lhld entsp! sphl lhld aret! mov a,l! mov b,h! ret ; ; data areas ; efcb: db empty ; 0e5=available dir entry rodsk: dw 0 ; read only disk vector dlog: dw 0 ; logged-in disks if MPM rlog: dw 0 ; removeable logged-in disks tlog: dw 0 ; removeable disk test login vector ntlog: dw 0 ; new tlog vector rem$drv: ds byte ; curdsk removable drive switch ; 0 = permanent drive, 1 = removable drive endif if not BANKED xdmaad equ $ curdma ds word ; current dma address endif if not MPM buffa: ds word ; pointer to directory dma address endif ; ; curtrka - alloca are set upon disk select ; (data must be adjacent, do not insert variables) ; (address of translate vector, not used) cdrmaxa:ds word ; pointer to cur dir max value (2 bytes) curtrka:ds word ; current track address (2) curreca:ds word ; current record address (3) drvlbla:ds word ; current drive label byte address (1) lsn$add:ds word ; login sequence # address (1) ; +1 -> bios media change flag (1) dpbaddr:ds word ; current disk parameter block address checka: ds word ; current checksum vector address alloca: ds word ; current allocation vector address dirbcba:ds word ; dir bcb list head dtabcba:ds word ; data bcb list head hash$tbla: ds word ; directory hash table address ds byte ; directory hash table bank addlist equ $-dpbaddr ; address list size ; ; buffer control block format ; ; bcb format : drv(1) || rec(3) || pend(1) || sequence(1) || ; 0 1 4 5 ; ; track(2) || sector(2) || buffer$add(2) || ; 6 8 10 ; ; bank(1) || link(2) ; 12 13 ; ; sectpt - offset obtained from disk parm block at dpbaddr ; (data must be adjacent, do not insert variables) sectpt: ds word ; sectors per track blkshf: ds byte ; block shift factor blkmsk: ds byte ; block mask extmsk: ds byte ; extent mask maxall: ds word ; maximum allocation number dirmax: ds word ; largest directory number dirblk: ds word ; reserved allocation bits for directory chksiz: ds word ; size of checksum vector offset: ds word ; offset tracks at beginning physhf: ds byte ; physical record shift phymsk: ds byte ; physical record mask dpblist equ $-sectpt ; size of area ; ; local variables ; drec ds word ; directory record number blk$off: ds byte ; record offset within block last$off: ds byte ; last offset within new block last$drive: ds byte ; drive of last new block last$block: ds word ; last new block ; The following two variables are initialized as a pair on entry dir$cnt: ds byte ; direct i/o count mult$num: ds byte ; multi-sector number tranv: ds word ; address of translate vector lock$unlock: make$flag: rmf: ds byte ; read mode flag for open$reel incr$pdcnt: dirloc: ds byte ; directory flag in rename, etc. free$mode: linfo: ds byte ; low(info) dminx: ds byte ; local for diskwrite if MPM searchl:ds byte ; search length endif if BANKED searcha:ds word ; search address endif if BANKED save$xfcb: ds byte ; search xfcb save flag endif single: ds byte ; set true if single byte allocation map if MPM seldsk: ds byte ; currently selected disk endif seldsk: ds byte ; disk on entry to bdos rcount: ds byte ; record count in current fcb extval: ds byte ; extent number and extmsk save$mod: ds byte ; open$reel module save field vrecord:ds byte ; current virtual record if not MPM curdsk: db 0ffh ; current disk endif adrive: db 0ffh ; current blocking/deblocking disk arecord:ds word ; current actual record ds byte save$ranr: ds 3 ; random record save area arecord1: ds word ; current actual block# * blkmsk attributes: ds byte ; make attribute hold area readf$sw: ds byte ; BIOS read/write switch ;******** following variable order critical ***************** if MPM mult$cnt: ds byte ; multi-sector count pdcnt: ds byte ; process descriptor count endif high$ext: ds byte ; fcb high ext bits if BANKED xfcb$read$only: ds byte ; xfcb read only flag endif if MPM curdsk: db 0ffh ;current disk packed$dcnt: ds 3 ; pdaddr: ds word ; ;************************************************************ cur$pos: ds word ; prv$pos: ds word ; sdcnt: ds word ; sdblk: ds word ; sdcnt0: ds word ; sdblk0: ds word ; dont$close: ds byte ; open$cnt: ; mp/m temp variable for open lock$cnt: ds word ; mp/m temp variable for lock file$id: ds word ; mp/m temp variable for lock deleted$files: ds byte lock$shell: ds byte lock$sp: ds word set$ro$flag: ds byte check$disk: ds byte flushed: ds byte fcb$cks$valid: ds byte ; mp/m variables * endif ; local variables for directory access dptr: ds byte ; directory pointer 0,1,2,3 save$hash: ds 4 ; hash code save area if BANKED copy$cr$init: ds byte ; copy$cr$only initialization value else hashmx: ds word ; cdrmax or dirmax xdcnt: ds word ; empty directory dcnt endif if MPM xdcnt: ds word ; empty directory dcnt xdblk: ds word ; empty directory block dcnt: ds word ; directory counter 0,1,...,dirmax dblk: ds word ; directory block index endif search$user0: ds byte ; search user 0 for file (open) user0$pass: ds byte ; search user 0 pass flag fcbdsk: ds byte ; disk named in fcb if MPM make$xfcb: ds 1 find$xfcb: ds 1 endif log$fxs:db 15,16,17,19,22,23,30,35,99,100,102,103,0 rw$fxs: db 20,21,33,34,40,41,0 sc$fxs: db 16,18,0 if MPM comp$fcb$cks: ds byte ; compute fcb checksum flag endif if BANKED pw$fcb: ds 12 ;1 | db 0 ;2 | pw$mode: db 0 ;3 |- Order critical db 0 ;4 | db 0 ;5 | df$password: ds 8 if MPM ds 120 endif endif phy$off: ds byte curbcba: ds word if BANKED lastbcba: ds word rootbcba: ds word emptybcba: ds word seqbcba: ds word buffer$bank: ds byte endif track: ds word sector: ds word ; ************************** ; Blocking/Deblocking Module ; ************************** deblock$dta: lhld dtabcba if BANKED cpi 4! jnz deblock deblock$flush: ; de = addr of 1st bcb mov e,m! inx h! mov d,m ; Search for dirty bcb with lowest track # lxi h,0ffffh! shld track! xchg deblock$flush1: ; Does current drive own bcb? lda adrive! cmp m! jnz deblock$flush2 ;no ; Is bcb's buffer pending? xchg! lxi h,4! dad d! mov a,m xchg! inr a! jnz deblock$flush2 ; no ; Is bcb(6) < track? push h! inx d! inx d! xchg mov e,m! inx h! mov d,m ; Subdh computes hl = de - hl lhld track! call subdh! pop h! jnc deblock$flush2 ; no ; yes - track = bcb(6) , sector = addr(bcb) xchg! shld track! xchg! shld sector deblock$flush2: ; Is this the last bcb? call get$next$bcba! jnz deblock$flush1 ; no - hl = addr of next bcb ; Does track = ffff? lxi h,track! call test$ffff! rz ; yes - no bcb to flush ; Flush bcb located by sector lhld sector! xra a! mvi a,4! call deblock lhld dtabcba! jmp deblock$flush ; Repeat until no bcb's to flush endif deblock: ; BDOS Blocking/Deblocking routine ; a = 1 -> read command ; a = 2 -> write command ; a = 3 -> locate command ; a = 4 -> flush command ; a = 5 -> directory update push a ; Save z flag and deblock fx ; phy$off = low(arecord) & phymsk ; low(arecord) = low(arecord) & ~phymsk call deblock8 lda arecord! mov e,a! ana b! sta phy$off mov a,e! ana c! sta arecord if BANKED pop a! push a! cnz get$bcba endif shld curbcba! call getbuffa! shld curdma ; hl = curbcba, de = .adrive, c = 4 call deblock9 ; Is BCB discarded? mov a,m! inr a! jz deblock2 ; yes ; Is command flush? pop a! push a! cpi 4! jnc deblock1 ; yes ; Is referenced physical record already in buffer? call compare! jz deblock45 ; yes xra a deblock1: ; Does buffer contain an updated record? call deblock10 cpi 5! jz deblock15 mov a,m! ora a! jz deblock2 ; no deblock15: ; Reset record pending flag mvi m,0 ; Save arecord lhld arecord! push h! lda arecord+2! push a ; Flush physical record buffer call deblock9 xchg! call move ; Select drive to be flushed lxi h,curdsk! lda adrive! cmp m! cnz disk$select1 ; Write record if drive logged-in mvi a,1! cz deblock$io ; Restore arecord pop b! pop d! call set$arecord ; Restore selected drive call curselect deblock2: ; Is deblock command flush | dir write? pop a! cpi 4! rnc ; yes - return ; Is deblock command write? push a! cpi 2! jnz deblock25 ; no ; Is blk$off < last$off lxi h,last$off! lda blk$off! cmp m! jnc deblock3 ; no deblock25: ; Discard BCB on read operations in case ; I/O error occurs lhld curbcba! mvi m,0ffh ; Read physical record buffer mvi a,2! jmp deblock35 deblock3: ; last$off = blk$off + 1 inr a! mov m,a ; Place track & sector in bcb xra a deblock35: call deblock$io deblock4: call deblock9 ; phypfx = adrive || arecord call move! mvi m,0 ; zero pending flag if BANKED ; Zero logical record sequence inx h! call set$bcb$seq endif deblock45: ; recadd = phybuffa + phy$off*80h lda phy$off! inr a! lxi d,80h! lxi h,0ff80h deblock5: dad d! dcr a! jnz deblock5 xchg! lhld curdma! dad d ; If deblock command = locate then buffa = recadd; return pop a! cpi 3! jnz deblock6 shld buffa! ret deblock6: xchg! lhld dmaad! lxi b,80h ; If deblock command = read cpi 1 if BANKED jnz deblock7 ; then move to tpa lda common$base+1! dcr a! cmp d! jc move$tpa lda buffer$bank! mov c,a! mvi b,1! call deblock12 lxi b,80h! jmp move$tpa deblock7: else jz move$tpa ; then move to dma endif ; else move from dma xchg if BANKED lda common$base+1! dcr a! cmp h! jc deblock75 lda buffer$bank! mov b,a! mvi c,1! call deblock12 lxi b,80h deblock75: endif call move$tpa ; Set physical record pending flag for write command call deblock10! mvi m,0ffh ret deblock8: lda phymsk! mov b,a! cma! mov c,a! ret deblock9: lhld curbcba! lxi d,adrive! mvi c,4! ret deblock10: lxi d,4 deblock11: lhld curbcba! dad d! ret if BANKED deblock12: push h! push d! call xmovef pop d! pop h! ret endif deblock$io: ; a = 0 -> seek only ; a = 1 -> write ; a = 2 -> read push a! call seek if BANKED lda buffer$bank! call setbnkf endif mvi c,1 pop a! dcr a jz wrbuff cp rdbuff ; Move track & sector to bcb call deblock10! inx h! inx h lxi d,track! mvi c,4! jmp move if BANKED get$bcba: shld rootbcba lxi d,-13! dad d! shld lastbcba call get$next$bcba! push h ; Is there only 1 bcb in list? call get$next$bcba! pop h! rz ; yes - return xchg! lxi h,0! shld emptybcba! shld seqbcba xchg get$bcb1: ; Does bcb contain requested record? shld curbcba! call deblock9! call compare! jz get$bcb4 ; yes ; Is bcb discarded? lhld curbcba! mov a,m! inr a! jnz get$bcb11 ; no xchg! lhld lastbcba! shld emptybcba! jmp get$bcb14 get$bcb11: ; Does bcb contain record from current disk? lda adrive! cmp m! jnz get$bcb15 ; no xchg! lxi h,5! dad d! lda phy$msk ; Is phy$msk = 0? ora a! jz get$bcb14 ; yes ; Does bcb(5) [bcb sequence] = phymsk? cmp m! jnz get$bcb14 ; no lhld seqbcba! mov a,l! ora h! jnz get$bcb14 lhld lastbcba! shld seqbcba get$bcb14: xchg get$bcb15: ; Advance to next bcb - list exhausted? push h! call get$next$bcba! pop d! jz get$bcb2 ; yes xchg! shld lastbcba! xchg! jmp get$bcb1 get$bcb2: ; Matching bcb not found ; Was a sequentially accessed bcb encountered? lhld seqbcba! mov a,l! ora h! jnz get$bcb25 ; yes ; Was a discarded bcb encountered? lhld emptybcba! mov a,l! ora h! jz get$bcb3 ; no get$bcb25: shld lastbcba get$bcb3: ; Insert selected bcb at head of list lhld lastbcba! call get$next$bcba shld curbcba! call get$next$bcba xchg! call last$bcb$links$de lhld rootbcba! mov e,m! inx h! mov d,m lhld curbcba! lxi b,13! dad b mov m,e! inx h! mov m,d lhld curbcba! xchg! lhld rootbcba mov m,e! inx h! mov m,d! xchg! ret get$bcb4: ; BCB matched arecord lhld curbcba! lxi d,5! dad d ; Does bcb(5) = phy$off? lda phy$off! cmp m! jz get$bcb5 ; yes ; Does bcb(5) + 1 = phy$off? inr m! cmp m! jz get$bcb5 ; yes call set$bcb$seq get$bcb5: ; Is bcb at head of list? lhld curbcba! xchg! lhld rootbcba mov a,m! inx h! mov l,m! mov h,a call subdh! ora l! xchg! rz ; yes jmp get$bcb3 ; no - insert bcb at head of list last$bcb$links$de: lhld lastbcba! lxi b,13! dad b mov m,e! inx h! mov m,d! ret get$next$bcba: lxi b,13! dad b! mov e,m! inx h! mov d,m xchg! mov a,h! ora l! ret set$bcb$seq: lda phy$off! mov m,a! ora a! rz lda phy$msk! inr a! mov m,a! ret endif if not MPM if not BANKED ds 112 last: org base + (((last-base)+255) and 0ff00h) - 112 olog: dw 0 rlog: dw 0 patch$flgs: dw 0,0 dw base+6 xra a! ret ; System Control Block SCB: ; Expansion Area - 6 bytes hashl: db 0 hash: dw 0,0 version: db 31h ; Utilities Section - 8 bytes util$flgs: dw 0,0 dspl$flgs: dw 0 dw 0 ; CLP Section - 4 bytes clp$flgs: dw 0 clp$errcde: dw 0 ; CCP Section - 8 bytes ccp$comlen: db 0 ccp$curdrv: db 0 ccp$curusr: db 0 ccp$conbuff: dw 0 ccp$flgs: dw 0 db 0 ; Device I/O Section - 32 bytes conwidth: db 0 column: db 0 conpage: db 0 conline: db 0 conbuffadd: dw 0 conbufflen: dw 0 conin$rflg: dw 0 conout$rflg: dw 0 auxin$rflg: dw 0 auxout$rflg: dw 0 lstout$rflg: dw 0 page$mode: db 0 pm$default: db 0 ctlh$act: db 0 rubout$act: db 0 type$ahead: db 0 contran: dw 0 conmode: dw 0 db 0 db 0 outdelim: db '$' listcp db 0 qflag: db 0 ; BDOS Section - 42 bytes scbadd: dw scb dmaad: dw 0080h olddsk: db 0 info: dw 0 resel: db 0 relog: db 0 fx: db 0 usrcode: db 0 dcnt: dw 0 searcha: dw 0 searchl: db 0 multcnt: db 1 errormode: db 0 searchchain: db 0,0ffh,0ffh,0ffh temp$drive: db 0 errdrv: db 0 dw 0 media$flag: db 0 dw 0 bdos$flags: db 0 stamp: db 0ffh,0ffh,0ffh,0ffh,0ffh commonbase: dw 0 error: jmp error$sub bdosadd: dw base+6 endif endif ; ************************ ; Directory Hashing Module ; ************************ ; Hash format ; xxsuuuuu xxxxxxxx xxxxxxxx ssssssss ; x = hash code of fcb name field ; u = low 5 bits of fcb user field ; 1st bit is on for XFCB's ; s = shiftr(mod || ext,extshf) if not BANKED hashorg: org base+(((hashorg-base)+255) and 0ff00h) endif init$hash: ; de = .hash table entry ; hl = .dir fcb push h! push d! call get$hash ; Move computed hash to hash table entry pop h! lxi d,hash! lxi b,4 if BANKED lda hash$tbla+2! call move$out else call movef endif ; Save next hash table entry address shld arecord1 ; Restore dir fcb address pop h! ret set$hash: ; Return if searchl = 0 ora a! rz ; Is searchl < 12 ? cpi 12! jc set$hash2 ; yes - hashl = 0 ; Is searchl = 12 ? mvi a,2! jz set$hash1 ; yes - hashl = 2 mvi a,3 ; hashl = 3 set$hash1: sta hashl xchg ; Is dir hashing invoked for drive? call test$hash! rz ; no xchg lda fx cpi 16! jz get$hash ; bdos fx = 16 cpi 35! jz set$hash15 cpi 20! jnc get$hash ; bdos fx = 20 or above set$hash15: mvi a,2! sta hashl ; bdos fx = 15,17,18,19, or 35 ; if fcb wild then hashl = 0, hash = fcb(0) ; else hashl = 2, hash = get$hash push h! call chk$wild! pop h! jnz get$hash set$hash2: xra a! sta hashl ; jmp get$hash get$hash: ; hash(0) = fcb(0) mov a,m! sta hash! inx h! xchg ; Don't compute hash for dir lbl & sfcb's lxi h,0! ani 20h! jnz get$hash6 ; b = 11, c = 8, ahl = 0 ; Compute fcb name hash (000000xx xxxxxxxxx xxxxxxxx) (ahl) lxi b,0b08h get$hash1: ; Don't shift if fcb(8) dcr c! push b! jz get$hash3 ; Don't shift if fcb(6) dcr c! dcr c! jz get$hash3 ; ahl = ahl * 2 dad h! adc a! push a! mov a,b ; is b odd? rar! jc get$hash4 ; yes ; ahl = ahl * 2 for even fcb(i) pop a! dad h! adc a get$hash3: push a get$hash4: ; a = fcb(i) & 7fh - 20h divided by 2 if even ldax d! ani 7fh! sui 20h! rar! jnc get$hash5 ral get$hash5: ; ahl = ahl + a mov c,a! mvi b,0 pop a! dad b! aci 0! pop b ; advance to next fcb char inx d! dcr b! jnz get$hash1 get$hash6: ; ahl = 000000xx xxxxxxxx xxxxxxxx ; Store low 2 bytes of hash shld hash+1! lxi h,hash ; hash(0) = hash(0) (000uuuuu) | xx000000 ani 3! rrc! rrc! ora m! mov m,a ; Does fcb(0) = e5h, 20h, or 21h? ani 20h! jnz get$hash9 ; yes ; bc = 00000mmm mmmeeeee, m = module #, e = extent ldax d! ani 1fh! mov c,a! inx d! inx d ldax d! ani 3fh! rrc! rrc! rrc! mov d,a ani 7! mov b,a! mov a,d! ani 0e0h! ora c! mov c,a ; shift bc right by # of bits in extmsk lda extmsk get$hash7: rar! jnc get$hash8 push a mov a,b! rar! mov b,a mov a,c! rar! mov c,a pop a! jmp get$hash7 get$hash8: ; hash(0) = hash(0) (xx0uuuuu) | 00s00000 mov a,b! ani 1! rrc! rrc get$hash9: rrc! ora m! mov m,a ; hash(3) = ssssssss lxi d,3! dad d! mov m,c! ret test$hash: lhld hash$tbla! mov a,l! ora h! inr a! ret search$hash: ; Does hash table exist for drive? call test$hash! rz ; no ; Has dir hash search been disabled? lda hashl! inr a! rz ; yes ; Is searchl = 0? lda searchl! ora a! rz ; yes ; hashmx = cdrmaxa if searchl ~= 1 ; dir$max if searchl = 1 lhld cdrmaxa! mov e,m! inx h! mov d,m xchg! dcr a! jnz search$h0 lhld dir$max search$h0: shld hashmx if BANKED ; call search$hash in resbdos, a = bank, hl = hash tbl addr lda hash$tbla+2! lhld hash$tbla! call srch$hash ; Was search successful? jnz search$h1 ; no ; Is directory read required? lda rd$dir$flag! ora a! mvi c,0 cnz r$dir2 ; yes if Z flag reset ; Is function = 18? lda fx! sui 18! rz ; Never reset dcnt for fx 18 ; Was media change detected by above read? lda hashl! inr a! cz setenddir ; yes xra a! ret ; search$hash successful search$h1: ; Was search initiated from beginning of directory? call end$of$dir! rnz ; no ; Is bdos fx = 15,17,19,22,23,30? call tst$log$fxs! rnz ; no ; Disable hash & return successful mvi a,0ffh! sta hashl lhld cdrmaxa! mov e,m! inx h! mov d,m! xchg dcx h! call set$dcnt$dblk1! xra a! ret else lhld hash$tbla! mov b,h! mov c,l lhld hashmx! xchg ; Return with Z flag set if dcnt = hashmx lhld dcnt! push h! call subdh! pop d! ora l! rz ; Push hashmx - dcnt (# of hashtbl entries to search) ; Push dcnt + 1 push h! inx d! xchg! push h ; Compute .hash$tbl(dcnt) dcx h! dad h! dad h! dad b search$h1: ; Advance hl to address of next hash$tbl entry lxi d,4! dad d! lxi d,hash ; Do hash u fields match? ldax d! xra m! ani 1fh! jnz search$h3 ; no ; Do hash's match? call search$h6! jz search$h4 ; yes search$h2: xchg! pop h search$h25: ; de = .hash$tbl(dcnt), hl = dcnt ; dcnt = dcnt + 1 inx h! xthl ; hl = # of hash$tbl entries to search ; decrement & test for zero ; Restore stack & hl to .hashtbl(dcnt) dcx h! mov a,l! ora h! xthl! push h ; Are we done? xchg! jnz search$h1 ; no - keep searching ; Search unsuccessful pop h! pop h ; Was search initiated from beginning of directory? call end$of$dir! rnz ; no ; Is fx = 15,17,19,22,23,30 & drive removeable? call tst$log$fxs! rnz ; no ; Disable hash & return successful mvi a,0ffh! sta hashl lhld cdrmaxa! mov e,m! inx h! mov d,m! xchg dcx h! call set$dcnt$dblk1! xra a! ret search$h3: ; Does xdcnt+1 = 0ffh? lda xdcnt+1! inr a! jz search$h5 ; yes ; Does xdcnt+1 = 0feh? inr a! jnz search$h2 ; no - continue searching ; Do hash's match? call search$h6! jnz search$h2 ; no ; xdcnt+1 = 0feh ; Open user 0 search ; Does hash u field = 0? mov a,m! ani 1fh! jnz search$h2 ; no ; Search successful search$h4: ; Successful search ; Set dcnt to search$hash dcnt-1 ; dcnt gets incremented by read$dir ; Also discard search$hash loop count lhld dcnt! xchg pop h! dcx h! shld dcnt! pop b ; Does dcnt&3 = 3? mov a,l! ani 03h! cpi 03h! rz ; yes ; Does old dcnt & new dcnt reside in same sector? mov a,e! ani 0fch! mov e,a mov a,l! ani 0fch! mov l,a call subdh! ora l! rz ; yes ; Read directory record call read$dir2 ; Has media change been detected? lda hashl! inr a! cz setenddir ; dcnt = -1 if hashl = 0ffh xra a! ret search$h5: ; xdcnt+1 = 0ffh ; Make search to save dcnt of empty fcb ; Is hash$tbl entry empty? mov a,m! cpi 0f5h! jnz search$h2 ; no search$h55: ; xdcnt = dcnt xchg! pop h! shld xdcnt! jmp search$h25 search$h6: ; hash compare routine ; Is hashl = 0? lda hashl! ora a! rz ; yes - hash compare successful ; b = 0f0h if hashl = 3 ; 0d0h if hashl = 2 mov c,a! rrc! rrc! rrc! ori 1001$0000b! mov b,a ; hash s field must be screened out of hash(0) ; if hashl = 2 ; Do hash(0) fields match? ldax d! xra m! ana b! rnz ; no ; Compare remainder of hash fields for hashl bytes push h! inx h! inx d! call compare pop h! ret endif fix$hash: call test$hash! rz lxi h,save$hash! lxi d,hash! lxi b,4 push h! push d! push b! call movef lhld hash$tbla! push h call get$dptra! call get$hash lhld dcnt! dad h! dad h pop d! dad d pop b! pop d! push d! push b if BANKED lda hash$tbla+2! call move$out else call movef endif pop b! pop h! pop d! jmp movef if not MPM if BANKED ds 1 last: org (((last-base)+255) and 0ff00h) - 1 db 0 endif else ds 192 last: org (((last-base)+255) and 0ff00h) - 192 ; bnkbdos patch area dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0,0,0,0,0 free$root: dw $-$ open$root: dw 0 lock$root: dw 0 lock$max: db 0 open$max: db 0 ; BIOS access table bios equ $ ; base of the bios jump table bootf equ bios ; cold boot function wbootf equ bootf+3 ; warm boot function constf equ wbootf+3 ; console status function coninf equ constf+3 ; console input function conoutf equ coninf+3 ; console output function listf equ conoutf+3 ; list output function punchf equ listf+3 ; punch output function readerf equ punchf+3 ; reader input function homef equ readerf+3 ; disk home function seldskf equ homef+3 ; select disk function settrkf equ seldskf+3 ; set track function setsecf equ settrkf+3 ; set sector function setdmaf equ setsecf+3 ; set dma function readf equ setdmaf+3 ; read disk function writef equ readf+3 ; write disk function liststf equ writef+3 ; list status function sectran equ liststf+3 ; sector translate endif end