Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

3945 lines
94 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
;*****************************************************************
;*****************************************************************
;
; error messages
IF MPM
dskmsg: db 'Bdos Err On '
dskerr: db ' : ',0
permsg: db 'Bad Sector',0
selmsg: db 'Select',0
rofmsg: db 'File '
rodmsg: db 'R/O',0
ELSE
dskmsg: db 'Bdos Err On '
dskerr: db ' : $' ;filled in by errflg
permsg: db 'Bad Sector$'
selmsg: db 'Select$'
rofmsg: db 'File '
rodmsg: db 'R/O$'
XERROR: DB 'X/Err '
XERR$ID:DB ' $'
ENDIF
;
IF BNKBDOS
setlret1:
mvi a,1
sta$ret:
sta aret
func$ret:
ret
entsp: ds 2
ENDIF
;
;*****************************************************************
;*****************************************************************
;
; common values shared between bdosi and bdos
usrcode:db 0 ;current user number
info: ds 2 ;information address
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 **
;** **
*****************************************************************
;*****************************************************************
;
dvers equ 30h ;version 3.0
; module addresses
;
; 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
;
; fixed addresses referenced in bios module are
; pererr (0009), selerr (000c), roderr (000f)
;
; error message handlers
;
;
rod$error: ;
;report read/only disk error
MVI B,2
JMP GOERR ;
;
rof$error: ;
;report read/only file error ;
MVI B,3
JMP GOERR
;
sel$error:
;report select error
MVI B,4
;
goerr:
;HL = .errorhandler, call subroutine
MOV H,B! MVI L,0FFH! SHLD ARET
IF MPM
call test$error$mode! jnz rtn$phy$errs
ELSE
LDA ERROR$MODE! ORA A! JNZ RTN$PHY$ERRS
ENDIF
MOV A,B! LXI H,PERERR-2! JMP BDOS$JMP
;
RTN$PHY$ERRS:
;
IF MPM
lda lock$shell! ora a! jnz lock$perr
ENDIF
LDA RETURN$FFFF! ORA A! JNZ 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
;
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
;
;*********************************************
; routines used by shell and lock/unlock
;*********************************************
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 curdsk, and fill
;the base addresses curtrka - alloca, then fill
;the values of the disk parameter block
MVI A,0FFH! STA CURDSK ; IN CASE SELECT FAILS
LDA SELDSK! mov c,a ;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 0000 in HL and z flag
;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
;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:
LDA SELDSK! STA CURDSK
IF NOT MPM
LHLD BUFFA! MOV A,H! ORA L! RNZ
LHLD DRVLBLA! MOV D,M! DCX H! MOV E,M
XCHG! SHLD BUFFA
ENDIF
INR A! RET ;select disk function ok
;
home:
;move to home position, then offset to start of dir
call homef ;move to track 00, sector 00 reference
;lxi h,offset ;mov c,m ;inx h ;mov b,m ;call settrkf ;
;first directory position selected
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
LXI H,0! SHLD DBLK ; DBLK = 0000
;curtrk, currec both set to 0000
ret
;
PASS$ARECORD:
LXI H,ARECORD
MOV E,M! INX H! MOV D,M! INX H! MOV B,M
RET
;
rdbuff:
;read buffer and check condition
CALL PASS$ARECORD
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
;wrtype = 0 => normal write operation
;wrtype = 1 => directory write operation
;wrtype = 2 => start of new block
CALL PASS$ARECORD
IF MPM
lda rem$drv! ora c! mov c,a
ENDIF
call writef ;current drive, track, sector, dma
diocomp: ;check for disk errors
ora a! rz ;
MOV B,A
CPI 3! JC GOERR
MVI B,1! JMP GOERR
;
seekdir:
;seek the record containing the current dir entry
;
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
;
lhld dcnt ;directory counter to HL
mvi c,dskshf! call hlrotr ;value to HL
;
; 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 ;
LXI H,ARECORD! MOV M,E! INX H! MOV M,D! INX H! MOV M,B
;
; jmp seek ;
;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
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 C,A ; BC = BC - DE
MOV A,B! SBB D! MOV B,A ;
;
lhld tranv! xchg ;BC=sector#, DE=.tran
call sectran ;HL = tran(sector)
mov c,l! mov b,h ;BC = tran(sector)
jmp setsecf ;sector selected
;ret
;
; 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! mvi h,0! ret ;with HL=00bb
getdmd:
dad b ;HL=.fcb(dm+i*2)
;double precision value returned
mov e,m! inx h! mov d,m! xchg! ret
;
index:
;compute disk block number from current fcb
call dm$position ;0...15 in register A
mov c,a! mvi b,0! call getdm ;value to HL
shld arecord! ret
;
allocated:
;called following index to see if block allocated
lhld 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
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,5! DAD D ; HL = .FCB(F'5)
MVI E,0111$1111B! MVI C,4
GET$ATTS$LOOP:
MOV A,M! PUSH A
RAL! MOV A,D! ADC A! MOV D,A
POP A! ANA E! MOV M,A
INX H! DCR C! JNZ GET$ATTS$LOOP
MOV A,D! ADD A! ADD A! ADD A! ADD A! 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! sta rcount ;rcount=fcb(reccnt)
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
lda seqio
cpi 02! jnz setfcb1! xra a ;check ranfill
setfcb1:
mov c,a ;=1 if sequential i/o
lda vrecord! add c! mov m,a ;fcb(nxtrec)=vrecord+seqio
xchg! lda rcount! mov m,a ;fcb(reccnt)=rcount
ret
;
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
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
IF MPM
lxi h,pdcnt! mov a,m
inx h! add m ; Add high$ext
ELSE
LXI H,HIGH$EXT! MOV A,M
ENDIF
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
;
CHEK$FCB:
LDA HIGH$EXT
; IF EXT & 0110$0000B = 0110$0000B THEN
; SET FCB(0) TO 0 (USER 0)
CPI 0110$0000B! JNZ CHEK$FCB1
LHLD INFO! XRA A! MOV M,A ; FCB(0) = 0
CHEK$FCB1:
JMP CHKSUM$FCB ;RET
;
CHECK$FCB:
IF MPM
xra a! sta check$fcb4
check$fcb1:
ENDIF
CALL CHEK$FCB! RZ
CHECK$FCB2:
;
IF MPM
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:
;
ENDIF
POP H ; DISCARD RETURN ADDRESS
IF MPM
check$fcb4:
nop
ENDIF
MVI A,10! JMP STA$RET
;
SET$FCB$CKS$FLAG:
MVI A,0FFH! STA COMP$FCB$CKS! RET
;
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$cdisk:
;set a "1" value in curdsk position of BC
LDA SELDSK
SET$CDISK1:
push b ;save input parameter
mov c,a ;ready parameter for shift
lxi h,1 ;number to shift
call hlrotl ;HL = mask to integrate
pop b ;original mask
mov a,c! ora l! mov l,a
mov a,b! ora h! mov h,a ;HL = mask or rol(1,curdsk)
ret
;
nowrite:
;return true if dir checksum difference occurred
lhld rodsk!
;
TEST$VECTOR:
LDA SELDSK
TEST$VECTOR1:
mov c,a! call hlrotr
mov a,l! ani 1b! ret ;non zero if curdsk bit on
;
set$ro:
;set current disk to read only
lxi h,rodsk! mov c,m! inx h! mov b,m
call set$cdisk ;sets bit to 1
shld rodsk
;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
;
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,true ;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 ARECORD! 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 ARECORD
dad d ;HL = .check(drec)
pop b ;recall true=0ffh or false=00 to C
inr c ;0ffh produces zero flag
jz initial$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 compcdr
rnc ;no message if so
IF MPM
call nowrite! cz flush$file0
ENDIF
jmp set$ro ;read/only disk set
IF MPM
test$dir$cs:
cmp m! jnz flush$files
ret
ENDIF
initial$cs:
;initializing the checksum
mov m,a! ret
;
;
wrdir:
;write the current directory entry, set checksum
CALL CHECK$WRITE
call newchecksum ;initialize entry
call setdir ;directory dma
mvi c,1 ;indicates a write directory operation
call wrbuff ;write the buffer
jmp setdata ;to data dma address
;ret
;
rd$dir:
;read a directory entry into the directory buffer
call setdir ;directory dma
call rdbuff ;directory record loaded
; jmp setdata to data dma address
;ret
;
setdata:
;set data dma address
lxi h,dmaad! jmp setdma ;to complete the call
;
setdir:
;set directory dma address
lxi h,buffa ;jmp setdma to complete call
;
setdma:
;HL=.dma address to set (i.e., buffa or dmaad)
mov c,m! inx h! mov b,m ;parameter ready
jmp setdmaf
;
;
IF NOT MPM
dir$to$user:
;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 dmaad ;destination is user dma address
mvi c,recsiz ;copy entire record
jmp move
;ret
ENDIF
;
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:
;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
jnc read$dir0
;yes, set dcnt to end of directory
jmp set$end$dir ;
; ret ;
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
push b ;save initialization flag C
call seek$dir ;seek proper record
call rd$dir ;read the directory record
pop b ;recall initialization flag
jmp checksum ;checksum the directory elt
;ret
;
;
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
;
scandm:
;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 scanm3
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
scanm3: ;
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 alloc 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:
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,3! inx h! mvi m,0
;cdrmax = 0000
call set$end$dir ;dcnt = enddir
;read directory entries and check for allocated storage
initial2:
mvi c,true! call read$dir
call end$of$dir! rz ;return if end of directory
;not end of directory, valid entry?
call getdptra ;HL = buffa + dptr
mvi a,empty! cmp m
jz initial2 ;go get another item
;
MVI A,20H! CMP M! JZ DRV$LBL
MVI A,70H! ANA M! JNZ INITIAL3
;
;now scan the disk map for allocated blocks
mvi c,1 ;set to allocated
call scandm
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
;ALL BLOCKS = 0 IN FCB DISK MAP
GET$DE2:
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:
mvi a,0ffh! sta dirloc ;changed if actually found
lxi h,searchl! mov m,c ;searchl = C
RET
;
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 home ;to start at the beginning
;(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
;
mvi c,false! call read$dir ;read next dir element
call end$of$dir! jz search$fin ;skip to end if so
;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
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
;
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
DCR A! STA FCB$EXISTS
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
LDA SAVE$XFCB! ORA A! JZ ENDSEARCH1
LDA XDCNT+1! CPI 0FEH! CZ SAVE$DCNT$POS0
JMP SEARCHN
ENDSEARCH1:
STA DIRLOC ; DIRLOC = 0
lda dcnt! ani dskmsk! sta lret
;lret = low(dcnt) and 11b
;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
; 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 ;
LHLD DBLK! SHLD XDBLK ;
SAVE$DCNT$POS$RET:
POP H! RET
;
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
;
delete:
;delete the currently addressed file
call check$write ;write protected?
CALL GET$ATTS! STA ATTRIBUTES
CALL CHK$PWS! PUSH A
CALL INIT$XFCB$SEARCH
MVI C,EXTNUM! CALL SEARCH ;SEARCH THROUGH FILE TYPE
POP B! JZ DELETE2
MOV A,B! ORA A! JNZ CHK$PW1
LDA ATTRIBUTES! RAL! JC DELETE015
LHLD INFO! CALL CHK$WILD! JZ DELETE015
IF MPM
call tst$olist
ENDIF
CALL CHECK$RODIR! JMP DELETE0
;
DELETE01:
;LOOP WHILE DIRECTORY MATCHES
JZ DELETE02
DELETE015:
IF MPM
call tst$olist
ENDIF
CALL CHECK$RODIR
CALL SEARCHN! JMP DELETE01
DELETE02:
;
LDA ATTRIBUTES! RAL! JC DELETE2
mvi c,extnum! call search ;search through file type
delete0:
;loop while directory matches
JZ DELETE2
DELETE1:
;set each non zero disk map entry to 0
;in the allocation vector
IF MPM
call chk$olist
ENDIF
call getdptra ;HL=.buff(dptr)
MOV A,M! ANI 10H
mvi m,empty
mvi c,0! CZ SCANDM ;alloc elts set to 0
call wrdir ;write the directory
call searchn ;to next element
jmp delete0 ;for another record
DELETE2:
CALL DOES$XFCB$EXIST! JNZ DELETE1! JMP COPY$DIR$LOC
;
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
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
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
jmp lefttst ;for another attempt
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! xchg ;DE=.fcb(C), source for copy
call getdptra ;HL=.buff(dptr), destination
pop b ;DE=source, HL=dest, C=length
RET
seek$copy:
;enter from close to seek and copy current element
call seek$dir ;to the directory element
jmp wrdir ;write the directory element
;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! POP H ; DISCARD RETURN ADDRESS
JMP SET$ARET
;
CHK$WILD:
MVI B,03FH! MVI C,11
CHK$WILD1:
INX H! MOV A,B! SUB M! ANA B! 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 conrol block. the file
;name and type are changed, but the reel number
;is ignored. the user number is identical
;
;VERIFIES NEW FILE NAME DOES NOT EXIST
;ALSO VERIFIES THAT NO WILD CHARS EXIST
;IN EITHER FILENAME
;
call check$write ;may be write protected
;VERIFY NO WILD CHARS EXIST IN 1ST FILENAME
CALL CHECK$WILD
CALL CHK$PASSWORD
;
CALL INIT$XFCB$SEARCH
;
;COPY USER NUMBER TO 2ND FILENAME
CALL COPY$USER$NO
;VERIFY NEW FILENAME DOES NOT ALREADY EXIST
SHLD SEARCHA
;
;VERIFY NO WILD CHARS EXIST IN 2ND FILENAME
CALL CHECK$WILD0
;
MVI C,EXTNUM! CALL SEARCHI1! CALL SEARCH1
JNZ FILE$EXISTS ; NEW FILENAME EXISTS
CALL DOES$XFCB$EXIST! CNZ DELETE1
;
CALL COPY$USER$NO
CALL INIT$XFCB$SEARCH
;search up to the extent field
mvi c,extnum! call search
rz
CALL CHECK$RODIR ;MAY BE READ-ONLY 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 searchn
JNZ RENAME0
RENAME1:
CALL DOES$XFCB$EXIST! JZ COPY$DIR$LOC
CALL COPY$USER$NO! JMP RENAME0
;
indicators:
;set file indicators for current fcb
CALL GET$ATTS ; CLEAR F5' THROUGH F8'
mvi c,extnum! call search ;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! CALL SEEK$COPY
call searchn
JZ COPY$DIR$LOC
jmp indic0
;
open:
;search for the directory entry, copy to fcb
mvi c,namlen! call search
OPEN1:
rz ;return with lret=255 if end
;not end of directory, copy fcb information
open$copy:
;(referenced below to copy fcb info)
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
push d ; save .buff(dptr)
call move ;from .buff(dptr) to .fcb(0)
;note that entire fcb is copied, including indicators
pop d! lxi h,extnum! dad d ;HL=.buff(dptr+extnum)
mov c,m ;C = directory extent number
; 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
LDAX D! CMP C! JZ SET$RC2
MVI A,0! JNC SET$RC1
MVI A,128! MOV B,M
SET$RC1:
MOV M,A
SET$RC2:
MOV A,B! STA ACTUAL$RC
RET
;
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 ACTUAL$RC ~= 0 THEN RCOUNT = ACTUAL$RC
PUSH H
LDA ACTUAL$RC! ORA A! JZ RESTORE$RC1
LXI D,(RECCNT-EXTNUM)! DAD D
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 SET$FCB$CKS$FLAG
CALL GETEXTA! MOV A,M! STA SAVE$EXT
CALL CLOSE$FCB
CALL GETDPTRA! LXI D,EXTNUM! DAD D! MOV C,M
CALL GETEXTA! LDA SAVE$EXT! MOV M,A
JMP SET$RC
CLOSE$FCB:
CALL GET$DIR$EXT! ; HL = .FCB(EXT)
MOV B,M! MOV M,A! INR A! SUB B! JNZ CLOSE3
ORA C! JZ CLOSE3
PUSH H! LXI D,(RECCNT-EXTNUM)! DAD D
MOV A,M! ORA A! JNZ CLOSE2
MVI M,80H
CLOSE2:
POP H
CLOSE3:
CALL RESTORE$RC ; RESTORE FCB(RECCNT)
mvi c,namlen! call search ;locate file
rz ;return if not found
;merge the disk map at info with that at buff(dptr)
lxi b,dskmap! call getdptra
dad b! xchg ;DE is .buff(dptr+16)
lhld info! dad b ;DE=.buff(dptr+16), HL=.fcb(16)
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)
lxi b,-(fcblen-extnum)! dad b! xchg! dad b
;DE = .fcb(extnum), HL = .buff(dptr+extnum)
ldax d ;current user extent number
;if fcb(ext) >= buff(fcb) then
;buff(ext) := fcb(ext), buff(rec) := fcb(rec)
cmp m! JNC DMSET0
XCHG ; UPDATE FCB IN MEMORY FROM DIR FCB
DMSET0:
IF MPM
push a
ENDIF
;fcb extent number >= dir extent number
mov m,a ;buff(ext) = fcb(ext)
;update directory record count field
lxi b,(reccnt-extnum)! dad b! xchg! dad b
;DE=.buff(reccnt), HL=.fcb(reccnt)
IF MPM
;under mp/m reccnt may have been extended
;by another process - if extents match, set
;both reccnt fields to the higher value
pop a! jnz dmset1
ldax d! cmp m! jc dmset1
mov m,a ; fcb(reccnt)=buff(reccnt)
dmset1:
ENDIF
mov a,m! stax d ;buff(reccnt)=fcb(reccnt)
endmerge:
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
jmp seek$copy ;ok to "wrdir" here - 1.4 compat
; ret ;
mergerr:
;elements did not merge correctly
CALL MAKE$FCB$INV
lxi h,lret! dcr m ;=255 non zero flag set
ret
;
SET$XDCNT:
LXI H,0FFFFH! SHLD XDCNT! RET
;
SET$DCNT$DBLK:
LHLD XDCNT! MVI A,1111$1100B! ANA L
MOV L,A! DCX H! SHLD DCNT ;
LHLD XDBLK! SHLD DBLK ;
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! JZ LRET$EQ$FF
CALL SET$DCNT$DBLK
;
call check$write ;may be write protected
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
;
; RETURN EARLY IF MAKING AN XFCB
LDA MAKE$XFCB! ORA A! RNZ
;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 c,fcblen-namlen ;number of bytes to fill
make0:
MOV M,D! inx h! dcr c! jnz 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"
XRA A! STA ACTUAL$RC
jmp setfwf
;
open$reel:
;close the current extent, and open the next one
;if possible. RMF is true if in read mode
CALL GETMODNUM! STA SAVE$MOD
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
JNZ OPEN$REEL0 ; JMP IF IN SAME MODULE
;
open$mod:
;extent number overflow, go to next module
INX H! INX H ;HL=.fcb(modnum)
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
mvi c,namlen! call search ;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
;call end$of$dir
jz open$r$err ;with lret = 1
IF MPM
call fix$olist$item
ENDIF
CALL SET$FCB$CKS$FLAG
jmp open$reel2
open$reel1:
;not end of file, open
CALL SET$FCB$CKS$FLAG
call open$copy
open$reel2:
call getfcb ;set parameters
xra a! STA VRECORD! jmp sta$ret ;lret = 0 ;
; ret ;with lret = 0
open$r$err:
CALL GETMODNUM! LDA SAVE$MOD! MOV M,A
CALL GETEXTA! LDA SAVE$EXT! MOV M,A
CALL SET$FCB$CKS$FLAG
;cannot move to next extent of this file
call setlret1 ;lret = 1
jmp setfwf ;ensure that it will not be closed
;ret
OPEN$REEL3:
MOV M,C ; INCREMENT EXTENT FIELD
CALL GET$DIR$EXT! MOV C,A
CALL RESTORE$RC
CALL SET$RC! JMP OPEN$REEL2
;
seqdiskread:
;sequential disk read operation
mvi a,1! sta seqio
;drop through to diskread
;
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
; xra a sta vrecord ;vrecord=00 (DONE BY OPEN$REEL)
;now check for open ok
lda lret! ora a! JNZ SETLRET1 ;stop at eof
recordok:
;arrive with fcb addressing a record to read
call index
;error 2 if reading unwritten data
;(returns 1 to be compatible with 1.4)
call allocated ;arecord=0000?
IF MPM
jnz recordok1
call test$disk$fcb! jnz diskread0
ENDIF
JZ SETLRET1
RECORDOK1:
;record has been allocated, read it
call atran ;arecord now a disk address
call seek ;to proper track,sector
call rdbuff ;to dma address
jmp setfcb ;replace parameter
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
;
seqdiskwrite:
;sequential disk write
mvi a,1! sta seqio
;drop through to diskwrite
;
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
;
LDA XFCB$READ$ONLY! ORA A
MVI A,3! JNZ SET$ARET
;
LDA HIGH$EXT! ANI 0100$0000B
; 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 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
call allocated
IF MPM
jz diskwrite2
;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
mov a,c! mvi c,0! push b
jmp diskwr10
not$unlocked:
inr a
ENDIF
mvi c,0 ;marked as normal write operation for wrbuff
jnz diskwr1
IF MPM
diskwrite2:
call test$disk$fcb! jnz diskwrite1
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:
CALL SET$FCB$CKS$FLAG
;allocated block number is in HL
shld arecord
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
;lda lret ora a rnz ;stop if non zero returned value
;ABOVE LINE REMOVED - LRET CANNOT BE NON-ZERO
push b ;save write flag
call atran ;arecord set
diskwr10:
;
MOV D,A ; SAVE LOW BYTE OF ARECORD RETURNED
; IN REGISTER A FROM ATRAN
;
lda seqio! dcr a! dcr a! jnz diskwr11 ;
pop b! push b! mov a,c! dcr a! dcr a ;
jnz diskwr11 ;old allocation
;
PUSH D ; SAVE LOW BYTE OF ARECORD ON STACK
;
lhld buffa! mov d,a ;zero buffa & fill
fill0: mov m,a! inx h! inr d! jp fill0 ;
call setdir! lhld arecord1 ;
mvi c,2 ;
fill1: shld arecord! push b! call seek! pop b ;
call wrbuff ;write fill record ;
lhld arecord! ;restore last record
mvi c,0 ;change allocate flag
lda blkmsk! mov b,a! ana l! cmp b!inx h ;
jnz fill1 ;cont until cluster is zeroed
;
POP A! STA ARECORD ; RESTORE ARECORD LOW BYTE
;
call setdata ; restore dma
diskwr11: ;
call seek ;to proper file position
pop b ;
;
LDA VRECORD! MOV B,A ; LOAD AND SAVE VRECORD
;
push b ;restore/save write flag (C=2 if new block)
;
LXI H,BLKMSK! ANA M! JZ WRITE ;
MVI C,0 ; SET C TO ZERO IF VRECORD DOES NOT LOCATE
; FIRST RECORD OF NEW BLOCK
WRITE:
;
call wrbuff ;written to disk
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 GETMODNUM! ANI 0100$0000B! JNZ DISK$WRITE3
MOV A,M! ORI 0100$0000B! MOV M,A
;RESET FCB FILE WRITE FLAG TO ENSURE T3' GETS
;RESET BY THE CLOSE FUNCTION
CALL RESET$FWF
DISK$WRITE3:
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
;(modnum has been set to 1100$0000b if previous bad seek)
xra a! sta seqio ;marked as random access operation
rseek1:
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
;
;CHECK MODULE # FIRST
PUSH D! CALL CHK$INV$FCB! POP D! JZ RANCLOSE
lxi h,modnum! dad d! mov a,b ;B=seek mod#
;could be overflow at eof, producing module#
;of 90H or 10H, so compare all but fwf
sub m! ani 3fh! JNZ RANCLOSE ;same?
;MODULE MATCHES, CHECK EXTENT
lxi h,extnum! dad d
MOV A,M! CMP C! JZ SEEKOK1 ;EXTENTS EQUAL
CALL COMPEXT! JNZ RANCLOSE
;EXTENT IS IN SAME DIRECTORY FCB
MOV M,C ; FCB(EXT) = C
CALL GET$DIR$EXT! MOV C,A
; 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 badseek
CALL SET$XDCNT ; RESET XDCNT FOR MAKE
IF MPM
call set$sdcnt
ENDIF
lxi h,extnum! dad d! mov m,c ;fcb(extnum)=ext#
INX H! INX H! MOV A,M! 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 b ;r/w flag to c (=0ffh if read)
push b ;everyone expects this item stacked
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:
CALL SET$FCB$CKS$FLAG
SEEKOK1:
pop b ;discard r/w flag
xra a! jmp sta$ret ;with zero set
badseek:
;fcb no longer contains a valid fcb, mark
;with 1100$000b in modnum field so that it
;appears as overflow with file write flag set
push h ;save error flag
CALL SET$FCB$CKS$FLAG
CALL MAKE$FCB$INV ; FLAG FCB AS INVALID
pop h ;and drop through
seekerr:
pop b ;discard r/w flag
mov a,l! sta lret ;lret=#, nonzero
;setfwf returns non-zero accumulator for err
RET ; FOLLOWING LINE REMOVED
; jmp setfwf ;flag set, so subsequent close ok
;ret
;
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 ;
;
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
MVI C,EXTNUM! CALL SEARCH
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)
mov e,a ;save cy
mov a,c! sub m! inx h ;ls byte
mov a,b! sbb m! inx h ;middle byte
mov a,e! sbb m ;carry if .fcb(ranrec) > directory
jc getnextsize ;for another try
;fcb is less or equal, fill from directory
mov m,e! dcx h! mov m,b! dcx h! mov m,c
getnextsize:
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
;
TMPSELECT:
LXI H,SELDSK! MOV A,M! PUSH A! MOV M,E
CALL CURSELECT! POP A! STA SELDSK! RET
;
XCURSELECT:
MVI A,0FFH! STA RETURN$FFFF
CALL CURSELECT
XRA A! STA RETURN$FFFF! RET
;
CURSELECT:
LDA SELDSK!
LXI H,CURDSK! CMP M! JZ TEST$FF$DSK
;SKIP IF SELDSK = CURDSK, FALL INTO SELECT
;
select:
;select disk info for subsequent input or output ops
lhld dlog! CALL TEST$VECTOR
MOV E,A! PUSH D ;SEND TO SELDSK, SAVE FOR TEST BELOW
call selectdisk! pop h ;recall dlog vector
cz sel$error ;returns true if select ok
;is the disk logged in?
mov a,l! ORA A
IF MPM
jz select1
lhld rlog! call test$vector
sta rem$drv! ret ; set rem$drv & return
select1:
ELSE
rnz ;return if bit is set
ENDIF
;disk not logged in, set bit and initialize
lhld dlog! mov c,l! mov b,h ;call ready
call set$cdisk! shld dlog ;dlog=set$cdisk(dlog)
IF MPM
lxi h,chksiz+1! mov a,m! ral! mvi a,0! jc select2
lhld rlog! mov c,l! mov b,h
call set$cdisk! shld rlog ;rlog=set$cdisk(rlog)
mvi a,1
select2:
sta rem$drv
ENDIF
jmp initialize
;ret
;
TEST$FF$DSK:
INR A! JZ SEL$ERROR
RET
;
SET$SELDSK:
LDA LINFO! STA SELDSK! RET
;
RESELECTX:
XRA A! STA HIGH$EXT! JMP RESELECT1
reselect:
;check current fcb to see if reselection necessary
MVI A,80H! MOV B,A! DCR A! MOV C,A
LHLD INFO! LXI D,7! XCHG! DAD D
MOV A,M! ANA B! STA XFCB$READ$ONLY
MOV A,M! ANA C! MOV M,A
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! CALL CLR$EXT
CALL GETRCNTA! MOV A,M! ANA B! JZ RESELECT1
MOV A,M! ANA C! MOV M,B
RESELECT1:
STA ACTUAL$RC
mvi a,true! sta resel ;mark possible reselect
lhld info! mov a,m ;drive select 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, save SELDSK
LDA SELDSK! sta olddsk ;olddsk=SELDSK
mov a,m! sta fcbdsk ;save drive code
ani 1110$0000b! mov m,a ;preserve hi bits
CALL SET$SELDSK
noselect:
CALL CURSELECT
;set user code
lda usrcode ;0...31
lhld info! ora m! mov m,a
ret
;
CHK$PASSWORD:
CALL GET$DIR$MODE! ANI 80H! JNZ CHK$PW! RET
;
GET$DIR$MODE:
LHLD DRVLBLA! MOV A,M! RET
;
CHK$PW: ; CHECK PASSWORD
CALL GET$XFCB! RZ ; A = XFCB OPTIONS
DCR A! CNZ CMP$PW! RZ
CHK$PW1: ; PASSWORD ERROR
POP H! MVI A,7! JMP SET$ARET
;
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
MOV M,A ; 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:
MVI B,0
GET$XFCB0:
LHLD INFO! MOV A,M! PUSH A
ORI 010H! MOV M,A! MVI C,EXTNUM
XRA A! CMP B! JNZ GET$XFCB00
CALL SEARCH! JMP GET$XFCB01
GET$XFCB00:
CALL SEARCHN
GET$XFCB01:
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! DCR A
CHK$XFCB$PASSWORD1:
PUSH H! CNZ CMP$PW! POP H! RZ
JMP CHK$PW1
;
CHK$PWS:
CALL GET$DIR$MODE! ANI 80H! RZ
CALL GET$XFCB
CHK$PWS1:
RZ! DCR A
CNZ CMP$PW! RNZ
MVI B,1! CALL GET$XFCB0! JMP CHK$PWS1
;
STAMP1:
LXI B,24! JMP STAMP3
STAMP2:
LXI B,28!
STAMP3:
;
IF MPM
push b!
call get$stamp$add! xchg
pop b
ELSE
LXI D,STAMP
ENDIF
CALL GETDPTRA! DAD B
MVI C,4! JMP MOVE ;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! call allocated
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
;ret
;
move$arecord:
lxi d,arecord! lxi h,packed$dcnt
mvi c,3! jmp move ;ret
;
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:
lhld ntlog! mov b,h! mov c,l
lda curdsk! call set$cdisk1! shld ntlog
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
mvi a,dvers! jmp sta$ret ;lret = dvers (high = 00)
ENDIF
; ret ;jmp goback
;
func13:
IF MPM
lhld dlog! shld info
call diskreset! jz reset$all
call reset$37
jmp func13$cont
reset$all:
ENDIF
;reset disk system - initialize to disk 0
lxi h,0! shld rodsk! shld dlog
IF MPM
shld rlog! shld tlog
func13$cont:
ENDIF
xra a! STA SELDSK ;note that usrcode remains unchanged
DCR A! STA CURDSK
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
;ret ;jmp goback
;
func14:
;select disk info
CALL SET$SELDSK ; SELDSK = LINFO
IF MPM
call curselect
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
JMP CURSELECT
ENDIF
;ret ;jmp goback
;
func15:
;open file
call clrmodnum ;clear the module number
call reselect
IF MPM
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:
lhld info! lda usrcode! mov m,a
call set$sdcnt
ENDIF
CALL RESET$CHKSUM$FCB ; SET INVALID CHECK SUM
CALL CHECK$WILD ; CHECK FOR WILD CHARS IN FCB
CALL GET$ATTS! ANI 1100$0000B ; A = ATTRIBUTES
IF MPM
cpi 1100$0000b! jnz att$ok
ENDIF
ANI 0100$0000B ; MASK OFF UNLOCK MODE
ATT$OK:
STA HIGH$EXT
IF MPM
mov b,a! ora a! rar! jnz att$set
mvi a,80h
att$set:
sta attributes! mov a,b
ENDIF
ANI 80H! JNZ CALL$OPEN
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
MVI A,0110$0000B! 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
; 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! CPI 060H! JNZ OPENX0 ; NO
ENDIF
; IS FILE UNDER USER 0 A SYSTEM FILE ?
MVI A,20H! STA ATTRIBUTES
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:
CALL RESET$CHKSUM$FCB
;
;DOES DIR LBL EXIST?
IF MPM
call get$dir$mode! ora a! jz openx1
ELSE
CALL GET$DIR$MODE! ORA A! JZ SET$FCB$CKS$FLAG
ENDIF
;YES - IS FILE PASSWORD PROTECTED FOR OPEN?
PUSH A! CALL GET$XFCB! POP B
ANI 0C0H! JZ OPENX1
;YES - HAVE PASSWORDS BEEN ENABLES BY DIR LBL?
MOV C,A! MOV A,B! ANI 80H! JZ OPENX1
;YES - CHECK PASSWORD
PUSH B! CALL CMP$PW! POP B! JZ OPENX1
MOV A,C! ANI 40H! CZ CHK$PW1
MVI A,080H! STA XFCB$READ$ONLY
OPENX1:
;
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:; open 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
call get$dir$mode
ELSE
CALL SET$FCB$CKS$FLAG! MOV A,B
ENDIF
;IS FILE ACCESS STAMPING ENABLED BY DIR LBL?
ANI 40H! RZ
CALL ENDOFDIR! RZ
;YES - IS FILE READ/WRITE?
CALL NOWRITE! RNZ ; CANNOT STAMP IF DISK READ ONLY
;YES - UPDATE FCB ACCESS STAMP
OPENX2:
CALL STAMP1
JMP SEEK$COPY
;
func16:
;close file
call reselect
CALL GET$ATTS! STA ATTRIBUTES
IF MPM
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 CHEK$FCB! MVI A,6! JNZ SET$ARET
CALL CLOSE
ENDIF
LDA LRET! INR A! RZ
CALL FUNC48 ; FLUSH BUFFERS
LDA ATTRIBUTES! ANI 1000$0000B! RNZ
IF MPM
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:
ENDIF
;
;HAS FILE BEEN WRITTEN TO SINCE IT WAS OPENED?
CALL GETMODNUM! ANI 40H! RZ
;YES - IS FILE UPDATE STAMPING ENABLED BY DIR LBL?
CALL GET$DIR$MODE! ANI 20H! RZ
;YES - DOES XFCB EXIST FOR FILE?
CALL GET$XFCB! RZ
;YES - UPDATE XFCB UPDATE STAMP
CALL STAMP2
JMP SEEK$COPY
;ret ;jmp goback
;
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! 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
IF NOT MPM
LXI H,DIR$TO$USER
PUSH H
ENDIF
JNZ SEARCHN
JMP SEARCH
;ret ;jmp goback
;
func18:
;search for next occurrence of a file name
IF MPM
xchg! shld searcha
ELSE
lhld searcha! shld info
ENDIF
;
ORI 1! JMP CSEARCH
;ret ;jmp goback
;
func19:
;delete a file
call reselectx
jmp delete
;ret ;jmp goback
;
func20:
;read a file
call reselect
CALL CHECK$FCB
jmp seqdiskread ;
;jmp goback
;
func21:
;write a file
call reselect
CALL CHECK$FCB
jmp seqdiskwrite ;
;jmp goback
;
func22:
;make a file
CALL GET$ATTS! STA ATTRIBUTES
XRA A! STA FCB$EXISTS
CALL CLR$EXT
call clrmodnum ; FCB MOD = 0
call reselect
CALL RESET$CHKSUM$FCB
CALL CHECK$WILD
CALL SET$XDCNT ; RESET XDCNT FOR MAKE
IF MPM
call set$sdcnt
ENDIF
CALL OPEN ; VERIFY FILE DOES NOT ALREADY EXIST
CALL RESET$CHKSUM$FCB
CALL END$OF$DIR! JNZ FILE$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
;DO ANY FCBS FOR FILE EXIST IN THE DIRECTORY?
LDA FCB$EXISTS! ORA A! JZ MAKEX04
;YES - DOES DIR LBL REQUIRE PASSWORDS?
CALL GET$DIR$MODE! ANI 80H! JZ MAKEX04
;YES - DOES XFCB EXIST WITH MODE 1 OR 2 PASSWORD?
CALL GET$XFCB! ANI 0C0H! JZ MAKEX04
;YES - CHECK PASSWORD
CALL CHK$XFCB$PASSWORD1
MAKEX04:
;
CALL MAKE
CALL RESET$CHKSUM$FCB
CALL END$OF$DIR! RZ ; RETURN IF MAKE UNSUCCESSFUL
;
;DOES DIR LBL EXIST?
CALL GET$DIR$MODE! ORA A! JZ MAKE4
;YES - DOES XFCB ALREADY EXIST FOR FILE
CALL GET$XFCB! JNZ MAKE000
;NO - DOES DIR LBL INVOKE AUTO XFCB CREATE
CALL GET$DIR$MODE! ANI 10H! JZ MAKE4
MVI A,0FFH! STA MAKE$XFCB! CALL MAKE! JNZ MAKE00
MVI C,NAMLEN! CALL SEARCH
CALL DELETE0! JMP LRET$EQ$FF
MAKE000:
;YES - IS THIS FIRST FCB FOR FILE?
LDA FCB$EXISTS! ORA A! JNZ MAKE4
MAKE00:
CALL INIT$XFCB
MAKE1:
CALL SET$FCB$CKS$FLAG
;DID USER SET PASSWORD ATTRIBUTE
LDA ATTRIBUTES! ANI 40H! JZ MAKE3
XCHG! LHLD XDMAAD! LXI B,8! DAD B! XCHG
LDAX D! ANI 0E0H! JNZ MAKE2
MVI A,80H
MAKE2:
PUSH A! CALL GETXFCB1! POP A! MOV M,A
CALL SET$PW! MOV M,B
MAKE3:
CALL OPENX2
MAKE4:
IF MPM
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
ENDIF
JMP SET$FCB$CKS$FLAG
;ret ;jmp goback
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
LDA ERROR$MODE! INR A! RZ
MVI A,40H! ADD C! STA XERR$ID
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
ELSE
LXI H,XERROR! JMP REPORT$ERR
ENDIF
;
func23:
;rename a file
call reselectx
jmp rename
;ret ;jmp goback
;
func24:
;return the login vector
lhld dlog! jmp sthl$ret ;
; ret ;jmp goback
;
func25:
;return selected disk number
LDA SELDSK! jmp sta$ret ;
; ret ;jmp goback
;
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 XCURSELECT
lhld alloca! jmp sthl$ret
; ret ;jmp goback
;
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
;ret ;jmp goback
ENDIF
;
func29:
;return r/o bit vector
lhld rodsk! jmp sthl$ret ;
; ret ;jmp goback
;
func30:
;set file indicators
CALL CHECK$WRITE
CALL CHECK$WILD
call reselectx
CALL CHK$PASSWORD
call indicators
jmp copy$dirloc ;lret=dirloc
;ret ;jmp goback
;
func31:
;return address of disk parameter block
CALL XCURSELECT
lhld dpbaddr
sthl$ret:
shld aret
ret ;jmp goback
;
func32:
;set user code
lda linfo! cpi 0ffh! jnz setusrcode
;interrogate user code instead
lda usrcode! jmp sta$ret ;lret=usrcode
; ret ;jmp goback
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 ;jmp goback
;
func33:
;random disk read operation
call reselect
CALL CHECK$FCB
jmp randiskread ;to perform the disk read
;ret ;jmp goback
;
func34:
;random disk write operation
call reselect
CALL CHECK$FCB
jmp randiskwrite ;to perform the disk write
;ret ;jmp goback
;
func35:
;return file size (0-65536)
call reselect
CALL CHECK$WILD
jmp getfilesize
;ret ;jmp goback
;
func36: equ setrandom
;set random record
;ret ;jmp goback
func37:
;
IF MPM
call diskreset
reset$37:
lhld info
ELSE
XCHG
ENDIF
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
LHLD DLOG! LDA CURDSK! CALL TEST$VECTOR1
RNZ ; RETURN IF CURDSK NOT RESET
MVI A,0FFH! STA CURDSK
; FORCE SELECT CALL IN NEXT CURSELECT
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:
;random disk write with zero fill of unallocated block
call reselect
CALL CHECK$FCB
mvi a,2! sta seqio
mvi c,false
call rseek1
cz diskwrite ;if seek successful
ret
;
func41 equ func$ret ;test & write
IF MPM
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 17! 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
;save user# and seldsk in location 0004h
lda usrcode
add a! add a! add a! add a! mov b,a
lda seldsk! ora b! sta base+0004h
mvi a,0ffh! sta chain$flg! jmp REBOOTX
ENDIF
;
func48: ;flush buffers
lxi h,diocomp! push h
lxi b,0ffffh! call setdmaf
pop h! jmp setdata
;
IF MPM
func49 equ func$ret
ELSE
func49: ;ccp chain query
lxi h,chain$flg! mov a,m! ora a! rz
mvi m,0! jmp lret$eq$ff
ENDIF
;
IF MPM
func50 equ func$ret
ELSE
func50: ;direct bios call
;DE -> function (1 byte)
; BC value (2 bytes)
; DE value (2 bytes)
xchg
mov a,m! inx h
mov c,m! inx h! mov b,m! inx h
mov e,m! inx h! mov d,m
mov l,a! add a! add l
lxi h,bios
add l! mov l,a!
mvi a,0! adc h! mov h,a! pchl
ENDIF
;
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 8 (01h): assign new password to dir lbl
call reselectx
call check$write
;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! call stamp1 ; create date & time stamp
sdl1:
;update date & time stamp
call stamp2
;verify password - new dir lbl falls through
call getxfcb1! call chk$xfcb$password1
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 seek$copy
;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
jmp seek$copy
;
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
;does xfcb exist for file?
call getxfcb! mvi a,0ffh! jz sta$ret
;yes - copy xfcb to user's fcb
lhld info! mvi c,nxtrec! jmp move ;ret
;
func103: ;write or update file xfcb
call reselectx
call check$wild
;does xfcb exist for file?
call set$xdcnt
call getxfcb! jnz wxfcb1
;no - does dir lbl exist in directory?
call get$dir$mode
ora a! mvi a,0ffh! jz sta$ret
;yes - does file exist in directory?
sta make$xfcb
mvi c,extnum! call search! 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
;set xfcb options data
push h! call getexta! pop d! xchg
mov a,m! ora a! jnz wxfcb2
ldax d! ani 1! jz seek$copy
wxfcb2:
ldax d! ani 0e0h! jnz wxfcb3
mvi a,80h
wxfcb3:
mov m,a! jmp sdl2
;
func104: ;set current date and time
IF MPM
call get$stamp$add
call copy$stamp
mvi m,0! ret
ELSE
lxi h,stamp
jmp copy$stamp
ENDIF
;
func105: ;get current date and time
IF MPM
call get$stamp$add
ELSE
lxi h,stamp
ENDIF
xchg
copy$stamp:
mvi c,4! jmp move ;ret
;
IF MPM
get$stamp$add:
call rlradr! lxi b,-5! dad b
ret
ENDIF
;
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
;
func107: ;return serial number
IF MPM
lhld sysdat! mvi l,181
ELSE
lxi h,serial
ENDIF
xchg! mvi c,6! jmp move
;
GOBACK0:
XRA A! STA RETURN$FFFF
LXI H,0FFFFH! SHLD ARET
goback:
;arrive here at end of processing to return to user
lda resel! ora a! jz retmon
;reselection may have taken place
LDA COMP$FCB$CKS! ORA A! CNZ SET$CHKSUM$FCB
LDA XFCB$READ$ONLY! ORA A! JZ GOBACK05
LHLD INFO! LXI D,7! DAD D
ORA M! MOV M,A
GOBACK05:
CALL GETEXTA! LDA HIGH$EXT! CPI 60H! JNZ GOBACK1
LXI D,-4! DAD D! MVI A,80H
GOBACK1:
ORA M! MOV M,A
LDA ACTUAL$RC! ORA A! JZ GOBACK2
CALL GETRCNTA! ORA M! MOV M,A
GOBACK2:
lhld info! mvi m,0 ;fcb(0)=0
lda fcbdsk! ora a! jz retmon
;restore disk number
mov m,a ;fcb(0)=fcbdsk
lda olddsk! STA SELDSK
;
; return from the disk monitor
retmon:
lhld entsp! sphl
lhld aret! mov a,l! mov b,h! ret
;
;
; data areas
;
; initialized data
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: db 0 ;curdsk removable drive switch
;0 = permanent drive, 1 = removable drive
ENDIF
IF NOT BNKBDOS
xdmaad equ $
ENDIF
dmaad: dw tbuff ;initial dma address
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
curtrka:ds word ;current track address
curreca:ds word ;current record address
DRVLBLA:DS WORD ;CURRENT DRIVE LABEL BYTE ADDRESS
dpbaddr:ds word ;current disk parameter block address
checka: ds word ;current checksum vector address
alloca: ds word ;current allocation vector address
addlist equ $-DPBADDR ;address list size
;
; 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
dpblist equ $-sectpt ;size of area
;
; local variables
RETURN$FFFF: DS BYTE ;SEL ERR FLAG FOR FXS 27 & 31
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.
fcb$exists:
ds byte ;Make FCB exists flag
free$mode:
seqio: ds byte ;1 if sequential i/o
linfo: ds byte ;low(info)
dminx: ds byte ;local for diskwrite
searchl:ds byte ;search length
searcha:ds word ;search address
ACTUAL$RC:
DS BYTE ;DIRECTORY EXT RECORD COUNT
SAVE$XFCB:
DS BYTE ;SEARCH XFCB SAVE FLAG
single: ds byte ;set true if single byte allocation map
SELDSK: DS BYTE ;CURRENTLY SELECTED DISK
olddsk: 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
SAVE$EXT:
DS BYTE ;OPEN$REEL EXTENT SAVE FIELD
vrecord:ds BYTE ;current virtual record
arecord:ds word ;current actual record
DS BYTE
; SHELL FCB SAVE AREA
SAVE$RANR: DB 0,0,0 ;RANDOM RECORD SAVE AREA
arecord1: ds word ;current actual block# * blkmsk
IF NOT MPM
MULT$CNT: DB 1 ;MULTI-SECTOR COUNT
ERROR$MODE DB 0 ;BDOS ERROR MODE
ENDIF
ATTRIBUTES: DB 0 ;MAKE ATTRIBUTE HOLD AREA
IF NOT MPM
CHAIN$FLG: DB 0 ;CHAIN FLAG
STAMP: DB 0FFH,0FFH,0FFH,0FFH
ENDIF
;
;******** Following variable order critical *****************
IF MPM
mult$cnt: db 1 ;multi-sector count
pdcnt: db 0 ;process descriptor count
ENDIF
HIGH$EXT: DB 0 ;FCB HIGH EXT BITS
XFCB$READ$ONLY: DB 0 ;XFCB READ ONLY FLAG
CURDSK: DB 0 ;CURRENT DISK
IF MPM
; MP/M VARIABLES *
packed$dcnt: db 0,0,0 ;
pdaddr: dw 0 ;
;************************************************************
cur$pos: dw 0 ;
prv$pos: dw 0 ;
sdcnt: dw 0 ;
sdblk: dw 0 ;
sdcnt0: dw 0 ;
sdblk0: dw 0 ;
dont$close: db 0 ;
open$cnt: ;MP/M temp variaable for open
lock$cnt: dw 0 ;MP/M temp variable for lock
file$id: dw 0 ;MP/M temp variable for lock
deleted$files: db 0
lock$shell: db 0
lock$sp: dw 0
set$ro$flag: db 0
check$disk: db 0
flushed: db 0
fcb$cks$valid: db 0
; MP/M VARIABLES *
ENDIF
;
; local variables for directory access
dptr: ds byte ;directory pointer 0,1,2,3
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
USER0$PASS:
DS BYTE ;SEARCH USER 0 PASS FLAG
;
; local variables initialized by bdos at entry
;
resel: ds byte ;reselection flag
fcbdsk: ds byte ;disk named in fcb
COMP$FCB$CKS: DS BYTE ;COMPUTE FCB CHECKSUM FLAG
SEARCH$USER0: DS BYTE ;SEARCH USER 0 FOR FILE (OPEN)
MAKE$XFCB: DB BYTE ;MAKE & SEARCH XFCB FLAG
FIND$XFCB: DB BYTE ;SEARCH FIND XFCB FLAG
;
DF$PASSWORD: DW 0,0,0,0
IF MPM
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
dw 0,0,0,0
ENDIF
;
IF MPM
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