	title	'bdos interface, bdos, version 2.2 feb. 1980'
;
;*******************************************************************
;*******************************************************************
;**								  **
;**	B A S I C   D I S K   O P E R A T I N G   S Y S T E M     **
;**							          **
;**               I N T E R F A C E   M O D U L E                 **
;** 								  **
;*******************************************************************
;*******************************************************************
;
;	Copyright (c) 1978, 1979, 1980
;	Digital Research
;	Box 579, Pacific Grove
;	California
;
;
;	20 January 1980
;
;
on	equ	0ffffh
off	equ	0000h
test	equ	off
;
	if	test
	org	0dc00h
	else	
	org	0800h
	endif
;
;	bios value defined at end of module
;
ssize	equ	24		;24 level stack
;
;	low memory locations
;
reboot	equ	0000h		;reboot system
ioloc	equ	0003h		;i/o byte location
bdosa	equ	0006h		;address field of jmp bdos
;
;	bios access constants
;
bootf	set	bios+3*0	;cold boot function
wbootf	set	bios+3*1	;warm boot function
constf	set	bios+3*2	;console status function
coninf	set	bios+3*3	;console input function
conoutf	set	bios+3*4	;console output function
listf	set	bios+3*5	;list output function
punchf	set	bios+3*6	;punch output function
readerf	set	bios+3*7	;reader input function
homef	set	bios+3*8	;disk home function
seldskf	set	bios+3*9	;select disk function
settrkf	set	bios+3*10	;set track function
setsecf	set	bios+3*11	;set sector function
setdmaf	set	bios+3*12	;set dma function
readf	set	bios+3*13	;read disk function
writef	set	bios+3*14	;write disk function
liststf set	bios+3*15	;list status function
sectran	set	bios+3*16	;sector translate
;
;	equates for now graphic characters
;
ctlc	equ	03h		;control c
ctle	equ	05h		;physical eol
ctlh	equ	08h		;backspace
ctlp	equ	10h		;prnt toggle
ctlr	equ	12h		;repeat line
ctls	equ	13h		;stop/start screen
ctlu	equ	15h		;line delete
ctlx	equ	18h		;=ctl-u
ctlz	equ	1ah		;end of file
rubout	equ	7fh		;char delete
tab	equ	09h		;tab char
cr	equ	0dh		;carriage return
lf	equ	0ah		;line feed
ctl	equ	5eh		;up arrow
;
	db	0,0,0,0,0,0
;
;	enter here from the user's program with function number in c
;	and information address in d,e
;
	jmp	bdose		;past parameter block
;
;	************************************************
;       *** relative locations 0009 - 000E           ***
;	************************************************
;
pererr:	dw	persub		;permanent error subroutine
selerr:	dw	selsub		;select error subroutine
roderr:	dw	rodsub		;ro disk error subroutine
roferr:	dw	rofsub		;ro file error subroutine
;
;
bdose:				;arrive here from user programs
	xchg
	shld	info
	xchg			;info=de, de=info
	mov	a,e
	sta	linfo		;linfo = low(info) - don't equ
	lxi	h,0
	shld	aret		;return value defaults to 0000
				;save user's stack pointer, set to local stack
	dad	sp
	shld	entsp		;entsp = stackptr
	lxi	sp,lstack	;local stack setup
	xra	a               
	sta	fcbdsk
	sta	resel		;fcbdsk,resel=false
	lxi	h,goback	;return here after all functions
	push	h		;jump goback equivalent to ret
	mov	a,c
	cpi	nfuncs	
	rnc			;skip if invalid #
	mov	c,e		;possible output character to c
	lxi	h,functab
	mov	e,a
	mvi	d,0		;de=func, hl=.ciotar
	dad	d
	dad	d
	mov	e,m
	inx	h
	mov	d,m		;de=functar(func)
	lhld	info		;info in de for later xchg
	xchg
	pchl			;dispatched
;
;	dispatch table for functions
;
functab:
	dw	wbootf, func1, func2, func3
	dw	punchf, listf, func6, func7
	dw	func8, func9, func10, func11 
;
diskf	equ	($-functab)/2		;disk funcs
;
	dw	func12, func13, func14, func15 
	dw	func16, func17, func18, func19
	dw	func20, func21, func22, func23 
	dw	func24, func25, func26, func27 
	dw	func28, func29, func30, func31
	dw	func32, func33, func34, func35 
	dw	func36, func37, func38, func39
	dw	func40
;
nfuncs	equ	($-functab)/2
;
;	error subroutines
;
persub:				;report permanent error
	lxi	h,permsg
	call	errflg		;to report the error
	cpi	ctlc
	jz	reboot		;reboot if response is otlc
	ret			;and ignore the error
;
selsub:				;report select error
	lxi	h,selmsg
	jmp	wait$err	;wait console before boot
;
rodsub:				;report write to read/only disk
	lxi	h,rodmsg
	jmp	wait$err	;wait console
;
rofsub:				;report read/only file
	lxi	h,rofmsg	;drop through to wait for console
;
Wait$err:
				;wait for response before boot
	call	errflg
	jmp	reboot
;
;	error messages
;
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$'
;
;
errflg:
				;report error to console, message address in hl
	push	h
	call	crlf		;stack mssg address, new line
	lda	curdsk
	adi	'A'
	sta	dskerr		;current disk name
	lxi	b,dskmsg
	call	print		;the error message
	pop	b
	call	print		;error mssage tail
				;jmp conin
				;to get the input character
				;(drop through to conin)
				;ret
;
;		console handlers
;
conin:
				;read console character to a
	lxi	h,kbchar
	mov	a,m
	mvi	m,0
	ora	a
	rnz			;no previous keyboard character ready
	jmp	coninf		;get character externally
				;ret
conech:				;read character with echo
	call	conin
	call	echoc
	rc			;echo character
				;character must be echoed before return
	push	psw
	mov	c,a
	call	tabout
	pop	psw
	ret			;with character in a
;
echoc:				;echo character if graphic
				;cr, lf, tab or backspace
	cpi	cr
	rz			;carriage return
	cpi	lf
	rz			;line feed
	cpi	tab
	rz			;tab
	cpi	ctlh
	rz			;backspace
	cpi	' '
	ret			;carry set if non graphic
;
conbrk:				;check for character ready
	lda	kbchar
	ora	a
	jnz	conb1		;skip if active kbchar
				;no active kbchar, check external break
	call	constf
	ani	1
	rz			;return if no character ready
				;character ready, read it
	call	coninf		;to a
	cpi	ctls
	jnz	conb0		;check stop screen function
				;found cls, read next character
	call	coninf		;to a
	cpi	ctlc
	jz	reboot		;ctlc implies reboot
				;not a reboot, act as if nothing happened
	xra	a
	ret			;with zero in accumulator
;
conb0:				;character in accum, save it
	sta	kbchar
;
conb1:	mvi	a,1		;return with true set in accumulator
	ret
;
conout:				;compute character position/write console
				;character from c
				;compcol = true if computing column position
	lda	compcol
	ora	a
	jnz	compout		;write the character, then compute the column
				;write console character from c
	push	b
	call	conbrk		;check for screen stop function
	pop	b
	push	b		;recall/save character
	call	conoutf		;externally, to console
	pop	b
	push	b		;recall/save character
				;may be copying to the list device
	lda	listcp
	ora	a
	cnz	listf		;to printer, if so
	pop	b		;recall character
;
compout:
	mov	a,c		;recall the character
				;and compute the column position
	lxi	h,column	;a = character, hl = .column
	cpi	rubout
	rz			;no column change if nulls
	inr	m		;column = column + 1
	cpi	' '
	rnc			;return if graphic
				;not graphic, reset column position
	dcr	m		;column = column - 1
	mov	a,m
	ora	a
	rz			;return if at zero
				;not at zero, may be backspace or end line
	mov	a,c		;character back to a
	cpi	ctlh
	jnz	notbacksp
				;backspace character
	dcr	m		;column = column - 1
	ret
;
notbacksp:
				;not a backspace character, eol7
	cpi	lf
	rnz			;return if not
				;end of line, column = 0
	mvi	m,0		;column = 0
	ret
;
ctlout:
				;send c character with possible
				;preceding up-arrow
	mov	a,c
	call	echoc		;cy if not graphic (or special case)
	jnc	tabout		;skip if graphic, tab, cr, lf, or ctlh
				;send preceding up arrow
	push	psw
	mvi	c,ctl
	call	conout		;up arrow
	pop	psw			
	ori	40h		;becomes graphic letter
	mov	c,a		;ready to print
				;(drop through to tabout)
;
tabout:
				;expand tabs to console
	mov	a,c
	cpi	tab
	jnz	conout		;direct to conout if not
				;tab encountered, move to next tab position
	tab0:
	mvi	c,' '
	call	conout		;another blank
	lda	column
	ani	111b		;column mod 8 = 0 7
	jnz	tab0		;back for another if not
	ret
;
;
backup:
				;back-up one screen position
	call	pctlh
	mvi	c,' '
	call	conoutf		;(drop through to pctlh)
;
pctlh:				;send ctlh to console without
				;affecting column count
	mvi	c,ctlh
	jmp	conoutf		;ret
;
crlfp:				;print #, cr, lf for ctlx, ctlu, ctlr functions
				;then move to strtcol (starting column)
	mvi	c,'#'
	call	conout
	call	crlf		;column = 0, move to position strtcol
;
crlfp0:
	lda	column
	lxi	h,strtcol
	cmp	m
	rnc			;stop when column reaches strtcol
	mvi	c,' '
	call	conout		;print blank
	jmp	crlfp0
;
crlf:
				;carriage return line feed sequence
	mvi	c,cr
	call	conout
	mvi	c,lf
	jmp	conout		;ret
;
print:				;print message until m(bc) = '$'
	ldax	b
	cpi	'$'
	rz			;stop on $, more to print
	inx	b
	push	b
	mov	c,a		;char to c
	call	tabout		;another character printed
	pop	b
	jmp	print
;
read:				;read to info address
				;(max length, current length, buffer)
	lda	column
	sta	strtcol		;save start for ctl-x, ctl-h
	lhld	info
	mov	c,m
	inx	h
	push	h
	mvi	b,0		;b = current buffer length,
				;c = maximum buffer length,
				;hl = next to fill - 1
readnx:				;read next character, bc, hl active
	push	b
	push	h		;blen, cmax, hl saved
;
readn0:
	call	conin		;next char in a
	ani	7fh		;mask parity bit
	pop	h
	pop	b		;reactivate counters
	cpi	cr
	jz	readen		;end of line?
	cpi	lf
	jz	readen		;also end of line
	cpi	ctlh
	jnz	noth		;backspace?
				;do we have any characters to back over?
	mov	a,b
	ora	a
	jz	readnx		;characters remain in buffer, backup one
	dcr	b		;remove one character
	lda	column
	sta	compcol		;col > 0
				;compcol > 0 marks repeat as length comput
	jmp	linelen		;uses same code as repeat

noth:				;not a backspace
	cpi	rubout
	jnz	notrub		;rubout char 7
				;rubout encountered, rubout if possible
	mov	a,b
	ora	a
	jz	readnx		;skip if len = 0
				;buffer has characters, resend las char
	mov	a,m
	dcr	b
	dcx	h		;a = last char
				;blen=blen-1, next to fill - 1 decremented
	jmp	rdech1		;act like this is an echo
;
notrub:				;not a rubout character, check end line
	cpi	ctle
	jnz	note		;physical end line?
				;yes, save active counters and force eol
	push	b
	push	h
	call	crlf
	xra	a
	sta	strtcol		;start position = 00
	jmp	readn0		;for another character
;
note: 				;not end of line, list toggle?
	cpi	ctlp
	jnz	notp		;skip if not ctlp
				;list toggle - change parity
	push	h		;save next to fill - 1
	lxi	h,listcp	;hl=.listcp flag
	mvi	a,1
	sub	m		;true-listop
	mov	m,a		;listcp - not listcp
	pop	h
	jmp	readnx		;for another char
;
notp:				;not a ctlp, line delete?
	cpi	ctlx
	jnz	notx
	pop	h		;discard start position
				;loop while column > strtcol
;
backx:
	lda	strtcol
	lxi	h,column
	cmp	m
	jnc	read		;start again
	dcr	m		;column = column - 1
	call	backup		;one position
	jmp	backx
;
notx:				;not a control x, control u?
				;not control-x, control-u?
	cpi	ctlu
	jnz	notu		;skip if not
				;delete line (ctlu)
	call	crlfp		;physical eol
	pop	h		;discard starting position
	jmp	read		;to start all over
;
notu:				;not line delete, repeat line?
	cpi	ctlr
	jnz	notr
;
linelen:			;repeat line, or compute line len (ctlh)
				;if compcol > 0
	push	b
	call	crlfp		;save line length
	pop	b
	pop	h
	push	h
	push	b
				;bcur, cmax active, beginning buff at hl
rep0:
	mov	a,b
	ora	a
	jz	rep1		;count len to 00
	inx	h
	mov	c,m		;next to print
	dcr	b
	push	b
	push	h		;count length down
	call	ctlout		;character echoed
	pop	h
	pop	b		;recall remaining count
	jmp	rep0		;for the next character
;
rep1:
				;end of repeat, recall lenghts
				;original bc still remains pushed
	push	h		;save next to fill
	lda	compcol
	ora	a		;>0 if computing length
	jz	readn0		;for another char if so
				;column position computed for ctlh
	lxi	h,column
	sub	m		;diff > 0
	sta	compcol		;count down below
				;move back compcol-column spaces
;
backsp:				;move back one more space
	call	backup		;one space
	lxi	h,compcol
	dcr	m
	jnz	backsp
	jmp	readn0 		;for next character
;
notr:				;not a ctlr, place into buffer
rdecho:
	inx	h
	mov	m,a		;character filled to mem
	inr	b		;blen = blen + 1
;
rdech1:				;look for a random control character
	push	b
	push	h		;active values saved
	mov   	c,a		;ready to print
	call	ctlout		;may be up-arrow c
	pop	h
	pop	b
	mov	a,m		;recall char
	cpi	ctlc		;set flags for reboot test
	mov	a,b		;move length to a
	jnz	notc		;skip if not a control c
	cpi	1		;control c, must be length 1
	jz	reboot		;reboot if blen = 1
				;length not one, so skip reboot
;
notc:				;not reboot, are we at end of buffer?
	cmp	c
	jc	readnx		;go for another if not
;
readen:				;end of read operation, store blen
	pop	h
	mov	m,b		;m(current len) = b
	mvi	c,cr
	jmp	conout		;return carriage, ret
;
func1:				;return console character with echo
	call	conech
	jmp	sta$ret
;
func2:	equ	tabout
				;write console character with tab expansion
;
func3:				;return reader character
	call	readerf
	jmp	sta$ret
;
;func4:	equated to punchf
				;write punch character
;
;func5:	equated to listf
				;write list character
				;write to list device
;
func6:				;direct console i/o - read if 0ffh
	mov	a,c
	inr	a
	jz	dirinp		;0ffh = > 00H, means input mode
	inr	a
	jz	constf		;0feh in c for status
				;direct output function
	jmp	conoutf			;
;
dirinp:
	call	constf		;status check
	ora	a
	jz	retmon		;skip, return 00 if not ready
				;character is ready, get it
	call	coninf		;to a
	jmp	sta$ret
;
func7:				;return io byte
	lda	ioloc
	jmp	sta$ret
;
func8:				;set i/o byte
	lxi	h,ioloc
	mov	m,c
	ret			;jmp coback
;
func9:				;write line until $ encountered
	xchg			;was lhld info
	mov	c,l
	mov	b,h		;bc=string address
	jmp	print		;out to console
;
func10:	equ	read
				;read a buffered console line
;
func11:				;check console status
	call	conbrk		;(drop through to sta$ret)
;
sta$ret:			;store the a register to aret
	sta	aret
;
func$ret:
	ret			;jmp goback (pop stack for non cp/m functions)
;
setlret1:			;set lret = 1
	mvi	a,1
	jmp	sta$ret
;
;		data areas
;
compcol:db	0		;true if computing column position
strtcol:db	0		;starting column position after read
column: db	0		;column position
listcp: db	0		;listing toggle
kbchar: db	0		;initial key char = 00
entsp:  ds	2		;entry stack pointer
	ds	ssize*2		;stack size
lstack:
;
;	end of basic i/o system
;
;*************************************************************************
;*************************************************************************
;
;	common values shared between bdos1 and bdos
;
usrcode:db	0		;current user number
curdsk: db	0		;current disk 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	22H		;version 2.2
;
;	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 "byte" 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
;
;per$error:			;report permanent error to user
;	lxi	h,pererr
;	jmp	goerr
;
;rod$error:			;report read/only file error
;	lxi	h,roferr	;jmp goerr
;
sel$error:			;report select error
 	lxi	h,selerr
;
goerr:				;hl = .errorhandler, call subroutine
	mov	e,m
	inx	h
	mov	d,m		;address of routine in de
	xchg
	pchl			;to subroutine
;
;
;	local subroutines for bios interface
;
move:
				;move data length of length c from source de to
				;destination give 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
	lda	curdsk
	mov	c,a		;current disk# to c
				;lsb of e = 0 of 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
				;de still contains .tran
	xchg
	shld	tranv		;.tran vector
	lxi	h,buffa		;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 no zero, use double dm
	mvi	m,false
;
retselect:
	mvi	a,true
	ora	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 accumlator
	lhld	curtrka
	mov	m,a
	inx	h
	mov	m,a		;curtrak=0000
	lhld	curreca
	mov	m,a
	inx	h
	mov	m,a		;currec=0000
				;curtrk, currec both set to 0000
	ret
;
rdbuff:				;read buffer and check condition
	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	writef		;current drive, track, sector, dma
;
diocomp:			;check for disk errors
	ora	a
	rz
	lxi	h,pererr
	jmp	goerr
;
seekdir:			;seek the record containing
				;the current dir entry
	lhld	dcnt		;directory counter to counter
	mvi	c,dskshf
	call	hlrotr		;value to hl
	shld	arecord
	shld	drec		;ready for seek
				; jmp seek		;
				;ret
;
;
seek:				;seek the track given by
				;arecord (actual record)
				;local equates for registers
	arech	equ	b
	arecl	equ	c	;arecord = bc
	crech	equ	d
	crecl	equ	e	;currec = de
	ctrkh	equ	h	
	ctrkl	equ	l	;curtrk	= hl
	tcrech	equ	h
	tcrecl	equ	l	;tcurrec = hl
				;load the registers from memory
	lxi	h,arecord
	mov	arecl,m
	inx	h
	mov	arech,m
	lhld	curreca
	mov	crecl,m
	inx	h
	mov	crech,m
	lhld	curtrka
	mov	a,m
	inx	h
	mov	ctrkh,m
	mov	ctrkl,a
				;loop while arecord < currec
seek0:
	mov	a,arecl
	sub	crecl
	mov	a,arech
	sbb	crech
	jnc	seek1		;skip if arecord > = currec
				;currec  = currec = sectpt
	push	ctrkh
	lhld	sectpt
	mov	a,crecl
	sub	l
	mov	crecl,a
	mov	a,crech
	sbb	h
	mov	crech,a
	pop	ctrkh
				;curtrk = curtrk - 1
	dcx	ctrkh
	jmp	seek0		;for another try
;
seek1:				;look while arecord > = (t:currec + sectpt)
	push	ctrkh
	lhld	sectpt
	dad	crech		;hl = currec + sectpt
	jc	seek2		;can be >ffffh
	mov	a,arecl
	sub	tcrecl
	mov	a,arech
	sbb	tcrech
	jc	seek2		;skip if t > arecord
				;currec = t
	xchg			;curtrk = curtrk + 1
	pop	ctrkh
	inx	ctrkh
	jmp	seek1		;for another try
;
seek2:  pop	ctrkh       	;arrive here with updated values
				;in each register
	push	arech
	push	crech
	push	ctrkh		;to stack for later
				;stack contains (lowest) bc=arecord,
				;de=currec, hl=curtrk
	xchg
	lhld	offset
	dad	d		;hl = curtrk + offset
	mov 	b,h
	mov 	c,l
	call	settrkf		;track set up
				;note that bc - curtrk is difference
				;to move in bios
	pop	d		;recall curtrk
	lhld	curtrka
	mov	m,e
	inx	h
	mov	m,d		;curtrk updated
				;now compute sector as arecord-currec
	pop	crech		;recall currec
	lhld	curreca
	mov	m,crecl
	inx	h
	mov	m,crech
	pop	arech		;bc=arecord, de=currec
	mov	a,arecl
	sub	crecl
	mov	arecl,a
	mov	a,arech
	sbb	crech
	mov	arech,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 # in extent
recsiz	equ	128		;record size
fcblen	equ	32		;file control block size
dirrec	equ	recsiz/fcblen	;directory elts/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	15		;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 indications
;
rofile	equ	9		;high order of first type char
invis	equ	10		;invisible file in dir command
;	equ	11		;reserved
;
;	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 = sbr(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
;
getdm:				;return disk map value from position
				;given by bc
	lhld	info		;base address of file control block
	lxi	d,dskmap
	dad	d		;hl = .diskmap
	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
	lda	blkshf		;shift count to reg a
	lhld	arecord
;
atran0:	
	dad	h
	dcr	a
	jnz	atran0		;shl(arecord,blkshf)
	shld	arecord1	;save shifted block #
	lda	blkmsk
	mov	c,a		;mask value to c
	lda	vrecord
	ana	c		;masked value in a
	ora	l
	mov	l,a		;to hl
	shld	arecord		;arecord = hl or (vrecord and blkmsk)
	ret
;
getexta:			;get current extent field address to a
	lhld	info
	lxi	d,extnum
	dad	d		;hl = .fcb (extnum)
	ret
;
getfcba:			;compute reccnt and nxtrec
				; addresses for get/setfcb
	lhld	info
	lxi	d,reccnt
	dad	d
	xchg			;de=.fcb(nxtrec)
	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(recs 1z-c)
	jnz	computecs0
	ret			;with checksum in a
;
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
	push	b		;save input parameter
	lda	curdsk
	mov	c,a		;ready parameter for shift
	lxi	h,1
	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
	lda	curdsk
	mov	c,a
	call	hlrotr
	mov	a,l
	ani	1b
	ret			;now zero if nowrite
;
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
	lxi	d,rofile
	dad	d		;offset to ro bit
	mov	a,m
	ral
	rnc			;return if not set
	lxi	h,roferr	
	jmp	goerr
;	jmp	rof$error	;exit to read only disk message
;
;
check$write:			;check for write protected disk
	call	nowrite
	rz			;ok to write if not rodsk
	lxi	h,roderr
	jmp	goerr
;	jmp	rod$error	;read only disk error
;
getdptra:			;compute the address of a directory element at
				;position 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
;
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 cdrmaz > 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	drec
	xchg
	lhld	chksiz
	call	subdh		;de-hl
	rnc			;skip checksum if past checksum vector size
				;drec < chksiz, so continue
	push	b		;save init flag
	call	compute$cs	;check sum value to a
	lhld	checka		;address of check sum vector
	xchg
	lhld	drec		;value of drec
	dad	d		;hl = .check(drec)
	pop	b		;recall true=0ffh or false=00 to c
	inr	c		;0ffh produces zero flag
	jz	initial$cs	;not initializing, compare
	cmp	m		;compute$cs - check(drec)7
	rz			;no message if ok
				;checksum error, ask we beyond 
				;the end of the disk?         
	call	compcdr
	rnc			;no message if so
	call	set$ro		;read/only disk set
	ret
;
initial$cs:			;initializing the checksum
	mov	m,a
	ret
;
;
wrdir:				;write the current directory entry set checksum
	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
;
;
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
;
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
	mov	a,m		;may be 0ffh
	inx	h
	cmp	m		;low(dcnt) = high (dcnt) ?
	rnz			;now 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 accumlator
				; 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	a,c
	rrc
	rrc
	rrc
	ani	11111b
	mov	c,a		;c shr 3 to c
	mov	a,b
	add	a
	add	a
	add	a
	add	a
	add	a		;b shl 5
	ora	c
	mov 	c,a		;bbbccccc to c
	mov	a,b
	rrc
	rrc
	rrc
	ani	11111b
	mov	b,a		;bc shr 3 to 
	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
	rrc			;in register c (to place bit back into
	dcr	d		; position), and
	jnz	rotr		;target alloc position in registers hl,
				; rotate and replace
	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
;
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 - bl
	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
;
initialize:			;initialize the current disk
				;lret = false 
				;set to true if $ file exists
				;compute the length of the
				;allocation vector - 2
	lhld	maxall	
	mvi	c,3		;perform maxall/8
				;number of bytes in alloc vector
				; is (maxall/8) + 1
	call	hlrotr
	inx	h		;hl = maxall/8 + 1
	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	;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
				;not empty, user ode the same?
	lda	usrcode
	cmp	m
	jnZ	pdollar
				;same user code, check for '$' submit
	inx	h
	mov	a,m		;first character
	sui	'$'		;dollar file?
	jnz	pdollar
				;dollar file found, mark in lret
	dcr	a
	sta	lret		;lret = 255
;
pdollar: 			;now scan the disk map for allocated blocks
	mvi	c,1		;set to allocated
	call	scandm
	call	setcdr		;set cdrmax to dcnt
	jmp	initial2	;for another entry
;
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
;
search:				;search for directory element of
				; length c at info
	mvi	a,0ffh
	sta	dirloc		;changed if actually found
	lxi	h,searchl
	mov	m,c		;searchl = c
	lhld	info
	shld	searcha		;searcha = info
	call	set$end$dir	;dcnt = endir
	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
	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 addres
	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
;
searchloop:
	mov	a,c
	ora	a
	jz	endsearch
	ldax	d
	cpi	'?'
	jz	searchok	;? matches all
				;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
	ldax	d		;fcb character
	jz	searchext	;skip to search extent
	sub	m
	ani	7fh		;mask-out flags/extent module
	jnz	searchn		;skip if not matched
	jmp	searchok	;matched character
;
searchext:			;a has fcb character
				;attempt an extent # match
	push	b		;save counters
	mov	c,m		;directory character to c
	call	compext		;compare user/dir char
	pop	b		;recall counters
	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	dcnt
	ani	dskmsk
	sta	lret		;lret = low (dcnt) and 11B
	lxi	h,dirloc
	mov	a,m
	ral
	rnc			;dirloc=0ffh
				;yes, change it to 0 to mark as found
	xra	a
	mov	m,a		;dirloc=0
	ret
;
search$fin:			;end of directory, or empty name
	call	set$end$dir	;may be artificial end
	mvi	a,255
	jmp	sta$ret					 	;
;     
delete:				;delete the currently addressed file
	call	check$write	;write protected?
	mvi	c,extnum
	call	search		;search through file type
;
delete0:			;loop while directory matches
	call	end$of$dir
	rz			;stop if ned
				;set each non zero disk map entry to 0
				;in the allocation vector
				;may be r/o file
	call	check$rodir	;ro disk error if found
	call	getdptra	;hl = .buff(dptr)
	mvi	m,empty
	mvi	c,0
	call	scandm		;alloc elts set to 0
	call	wrdir		;write the directory
	call	searchn		;to next element
	jmp	delete0		;for another record
;
get$block:			;given allocation vector position
				; bc, find the zero bit
				;closest to this position by
				; searching lef 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 reposit
	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$fcb:			;copy the entire file control block
	mvi	c,0
	mvi	e,fcblen	;start at 0, to fcblen-1
;	jmp	copy$dir
;
copy$dir:			;copy fcb information starting at c for e bytes
				;into the currently addressed directory entry
	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
	call 	move		;data moved
;
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
;
rename:				;rename the file described by the first half of
				;the currently addressed file control
				; block.  The
				;new name is contained in the last half of the
				;currently addressed file control block.
				;  The file
				;name and type are changed, but the reel number
				;is ignored.  The user number is identical
	call	check$write	;may be write protected
				;search up to the extent field
	mvi	c,extnum
	call	search
				;copy position 0
	lhld	info
	mov	a,m		;hl=.fcb(0), a=fcb(0)
	lxi	d,dskmap
	dad	d		;hl=.fcb(dskmap)
	mov	m,a		;fcb(dskmap)=fcb(0)
				;assume the same disk drive for new named fiel
rename0:
	call	end$of$dir
	rz			;stop at end of dir
				;not end of directory, rename next element
	call	check$rodir	;may be read-only file
				;element renamed, move to next
	mvi	c,dskmap
	mvi	e,extnum
	call	copy$dir
	call	searchn
	jmp	rename0
;
indicators:			;set file indicators for current fcb
	mvi	c,extnum
	call	search		;through file type
;
indic0:
	call	end$of$dir
	rz 			;stop at end of dir
				;not end of directory, continue to change
	mvi	c,0
	mvi	e,extnum	;copy name
	call	copy$dir
	call	searchn
	jmp	indic0
;
open:				;search for the directory entry, copy to fcb
	mvi	c,namlen
	call	search
	call	end$of$dir
	rz			;return with lret=255 if end
				;not end of directory. copy fcb information
open$copy:			;(referenced below to copy fcb info)
	call	getexta
	mov	a,m
	push	psw
	push	h		;save extent#
	call	getdptra
	xchg			;de = .buff (dptr)
	lhld	info		;hl=.fcb(0)
	mvi	c,nxtrec	;lenght of move operation
	push	d		;save .buff (dptr)
	call	move		;from .buff(dptr) to .fcb(0)
				;note that entire fcb is copied,
				; including indicators
	call	setfwf		;sets file write flag
	pop	d
	lxi	h, extnum
	dad	d		;hl=.buff(dptr+extnum)
	mov	c,m		;c = directory extent number
	lxi	h,reccnt
	dad	d		;hl = .buff (dptr + reccnt)
	mov	b,m		;b holds directory record count
	pop	h
	pop	psw
	mov	m,a		;restore extent number
				;hl = .user extent #, b - dir rec cnt,
				; c - dir extent #
				;if user ext < dir ext then user :
				; = 128 records
				;if user ext = dir ext then user :
				; - dir records
				;if user ext > dir ext then user: = 0 records
	mov	a,c
	cmp	m
	mov	a,b		;ready dir reccnt
	jz	open$rcnt	;if same, user gets dir reccnt
	mvi	a,0
	jc	open$rcnt	;user is larger
	mvi	a,128		;directory is larger
;
open$rcnt:			;a has record count to fill
	lhld	info
	lxi	d,reccnt
	dad	d
	mov	m,a	
	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
;
close:				;locate the directory element and re-write it
	xra	a
	sta	lret
	sta	dcnt
	sta	dcnt+1
	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
	mvi	c,namlen
	call	search		;locate file
	call	end$of$dir
	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 = .fcr(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
	jc	endmerge	;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)
	mov	a,m
	stax	d		;buff(reccnt)=fcb(reccnt)
;
endmerge:	
	mvi	a,true
	sta	fcb$copied	;mark as copied
	jmp	seek$copy	;ok to "wrdir" here - 1.4 compat
;							;
mergerr:			;elements did not merge correctly
	lxi	h,lret
	dcr	m		;=255 non zero flag set
	ret
;
make:				;create a new file by creating
				; a directory entry
				;then opening the file
	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	search		;length 1 match on empty entry
	call	end$of$dir	;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
	xchg			;de = info address
				;clear the remainder of the fcb
	lxi	h,namlen
	dad	d		;hl=.fcb(namlen)
	mvi	c,fcblen-namlen	;number of bytes to fill
	xra	a		;clear accumulator to 00 for fill
;
make0:
	mov	m,a
	inx	h
	dcr	c
	jnz	make0
	lxi	h,ubytes
	dad	d		;hl = .fcb(ubytes)
	mov	m,a		;fcb(ubytes) = 0
	call	setcdr		;may have extended the directory
				;now copy entry to the directory
	call	copy$fcb	;and set the file write flag to "1"
	jmp	setfwf
				;ret
;
open$reel:			;close the current extent, and
				; open the next one
				;if possible.  rmf is true if in read mode
	xra	a
	sta	fcb$copied	;set true if actually copied
	call	close		;close current extent
				;lret remains at enddir if we
				; cannot open the next e
	call	end$of$dir
	rz			;return if end
				;increment extent number
	lhld	info
	lxi	b,extnum
	dad	b		;hl = .fcb(extnum)
	mov	a,m
	inr	a
	ani	maxext
	mov	m,a		;fcb(extnum) = ++1
	jz	open$mod	;move to next module if zero
				;may be in the same extent group
	mov	b,a
	lda	extmsk
	ana	b
				;if result is zero, then not in the same group
	lxi	h,fcb$copied	;true if the fcb was copied to directory
	ana	m		;produces a 00 in accumulator if not written
	jz	open$reel0	;go to next physical extent
				;result is now zero, so we must
				; be in same logical ext
	jmp	open$reel1	;to copy fcb information

open$mod:			;extent number overflow, go to next module
	lxi	b,(modnum-extnum)
	dad	b		;hl = .fcb(modnum)
	inr	m		;fcb(modnum) = ++1
				;module number incremented, check for overflow
	mov	a,m
	ani	maxmod		;mask high order bits
	jz	open$r$err	;cannot overflow to zero
				;otherwise, ok to continue with new module
open$reel0:
	mvi	c,namlen
	call	search		;next extent found?
	call	end$of$dir
	jnz	open$reel1
				;end of file encountered
	lda	rmf
	inr	a		;0ffh becomes 00 if read
	jz	open$r$err	;with lret = 1
	call	make		;cannot be end of directory
	call	end$of$dir
	jz	open$r$err	;with lret = 1
	jmp	open$reel2
;
open$reel1:			;not end of file, open
	call	open$copy
;
open$reel2:		 
	call	getfcb		;set parameters
	xra	a
	jmp	sta$ret		;lret = 0			;
;	ret			;with lret = 0
;
open$r$err:			;cannot move to next extent of this file
	call	setlret1	;lret = 1
	jmp	setfwf		;ensure that it will not be closed
				;ret
;
seqdiskread:			;sequential disk read operation
	mvi	a,1
	sta	seqio
				;drop through to diskread
;
diskread			;(may enter from seqdiskread)
	mvi	a,true
	sta	rmf		;read mode flag = true (open$reel)
				;read the next record from the current fcb
	call	getfcb		;sets parameters for the read
	lda	vrecord
	lxi	h,rcount
	cmp	m		;vrecord-rcount
				;skip if rcount > vrecord
	jc	recordok	;not enough records in the extent
				;record count must be 128 to continue
	cpi	128		;vrecord = 1287
	jnz	diskeof		;skip if vrecord <> 128
	call	open$reel	;go to next extent if so
	xra	a
	sta	vrecord		;vrecord=00
				;now check for open ok
	lda	lret
	ora	a
	jnz	diskeof		;stoop 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=00007
	jz	diskeof		;record has been allocated, reat it
	call	atran		;arecord now a disk address
	call	seek		;to proper track, sector
	call	rdbuff		;to dma address
	jmp	setfcb		;replace parameter
;	ret							;
;
diskeof:
	jmp	setlret1	;lret = 1
				;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
	lhld	info		;hl = .fcb (0)
	call	check$rofile	;may be a read-only file
	call	getfcb		;to set local parameters
	lda	vrecord
	cpi	lstrec+1	;vrecord-128
				;skip if vrecord >lstrec
				;vrecord = 128, cannot open next extent
	jnc	setlret1	;lret=1					;
;
diskwr0:			;can write the next record, so continue
	call	index
	call	allocated
	mvi	c,0		;marked as normal write operation for wrbuff
	jnz	diskwr1		;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,0		;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:			;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
	push	b		;save write flag
	call	atran		;arecord set
	lda	seqio
	dcr	a
	dcr	a
	jnz	diskwr11
	pop	b
	push	b
	mov	a,c
	dcr	a
	dcr	a
	jnz	diskwr11	;old allocation
	push	h		;arecord in hl ret from atran
	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	h
	shld	arecord
	call	setdata
;
diskwr11:
	call	seek		;to proper file position
	pop	b
	push	b		;restore/save write flag (c=2 if new block)
	call	wrbuff		;written to disk
	pop	b		;c = 2 if a new block was allocated, 0 if not
				;increment record count if rcount<=vrecord
	lda	vrecord
	lxi	h,rcount
	cmp	m		;vrecord-rcount
	jc	diskwr2		;rcount<=vrecord
	mov	m,a
	inr	m		;rcount = vrecord + 1
	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
	push	psw		;save vrecord value
	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) = fcp(modnum) and 7fh
	pop	psw		;restore vrecord
;
noupdate:
				;check for end of extent,
				; if found attempt to open
				;next extent in preparation for next write
	cpi	lstrec		;vrecord=lstrec7
	jnz	diskwr3		;skip if not
				;may be random access write, if so we are done
				;change next
	lda	seqio
	cpi	1
	jnz	diskwr3		;skip next extent open op
				;update current fcb before going to next extent
	call	setfcb
	call	open$reel	;rmf-false
				;vrecord remains at lstrec causing eof if
				;no more directory space is available
	lxi	h,lret
	mov	a,m
	ora	a
	jnz	nospace		;space available, set vrecord = 255
	dcr	a
	sta	vrecord		;goes to 00 next time
;
nospace:
	mvi	m,0		;lret=00 for returned value
;
diskwr3:
 	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
	rar
	rar
	rar
	rar
	ani	1111b		;mod #
	mov	b,a		;b holds module#, c holds ext #
	pop	psw		;recall sought record #
				;check to insure that high byte of ran rec = 00
	inx	h
	mov	l,m		;l=high byte (must be 00)
	inr	l
	dcr	l
	mvi	l,6		;zero flag, l=6
				;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 for values
	lxi	h,extnum
	dad	d
	mov	a,c		;a-seek ext#
	sub	m
	jnz	ranclose	;tests for = extents
				;extents match, check mod #
	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	7fh
	jz	seekok
;
ranclose:
	push	b
	push	d		;recall parameters and fill
	call	close		;current extent failed
	pop	d
	pop	b		;recall parameters and fill
	mvi	l,3		;cannot close error # 3
	lda	lret
	inr	a
	jz	badseek
	lxi	h,extnum
	dad	d
	mov	m,c		;fcb(extnum)-ext#
	lxi	h,modnum	
	dad	d
	mov	m,b		;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
	lda	lret
	inr	a
	jz	badseek		;no dir space
				;file make operation successful
seekok:
	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	getmodnum	;hl = .modnum
	mvi	m,1100$0000b
	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
	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 getfile
				;size/setrandom
	xchg
	dad	d		;de = .buf(dprt) 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 = xxx? MMMM
	add	a
	add	a
	add	a
	add	a		;cy = ? a = MMMM 0000
	push	psw
	add	b
	mov	b,a		;cy = ? bc = MMMM EEEE ERRR RRRR
	push	psw		;possible second carry
	pop	h		;cy = lsb of L
	mov	a,l		;cy = lsb of A
	pop	h		;cy = lsb of L
	ora	l		;cy/cy = lsb of A
	ani	1		;A = 0000 000?  possible carry out
	ret
;
getfilesize:			;compute logical file size for current fcb
	mvi	c,extnum
	call	search		;zero the receiving ranrec field
	lhld	info
	lxi	d,ranrec
	dad	d
	push	h		;save position
	mov	m,d
	inx	h
	mov	m,d
	inx	h
	mov	m,d		;00 00 00
;
getsize:
	call	end$of$dir
	jz	setsize		;current fcb addressed by dptr
	call	getdptra
	lxi	d,reccnt	;ready for compute size
	call	compute$rr	;a = 0000 000?  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
	jmp	getsize
;
setsize:
	pop	h		;discard .fcb(ranrec)
	ret
;
setrandom:			;set random record from the current fcb
	lhld	info
	lxi	d,nxtrec	;ready params for computesize
	call	compute$rr	;de = info, a = cy, 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
;
select:				;select disk info for subsequent
				;input or output operations
	lhld	dlog
	lda	curdsk
	mov	c,a
	call	hlrotr
	push	h
	xchg			;save it for test below, send to seldsk
	call	selectdisk
	pop	h		;recall dlog vector
	cz	sel$error	;returns true if select ok
				;is the disk logged in?
	mov	a,l
	rar
	rc			;return if bit set
				;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)
	jmp	initialize
;	ret
;
curselect:
	lda	linfo
	lxi	h,curdsk
	cmp	m
	rz			;skip in linfo = curdsk
	mov	m,a		;curdsk=info
	jmp	select
;
reselect:			;check current fcb to see if reselection
				;necessary
	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 the drive code
	cpi	30
	jnc	noselect	;auto select function, save curdsk
	lda	curdsk
	sta	olddsk		;olddsk = curdsk
	mov	a,m
	sta	fcbdsk		;save drive code
	ani	1110$0000b
	mov	m,a		;preserve hi bits
	call	curselect
;
noselect:			;set user code
	lda	usrcode		;0...31
	lhld	info
	ora	m
	mov	m,a
	ret
;
;	individual function handlers
;
func12:				;return version number
	mvi	a,dvers
	jmp	sta$ret		;lret = dvers (high = 00)
;	ret			;jmp goback
;
;
func13:				;reset disk system - initialize to disk 0
	lxi	h,0
	shld	rodsk
	shld	dlog
	xra	a
	sta	curdsk		;note that user code remains unchanged
	lxi	h,tbuff
	shld	dmaad		;dmaad = tbuff
	call	setdata		;to data dma address
	jmp	select		;ret ;jmp goback
;
;
func14:	equ	curselect	;select disk info
;
;
func15:				;open file
	call	clrmodnum	;clear the module number
	call	reselect
	jmp	open
;
;
func16:				;close file
	call	reselect
	jmp	close
;
;
func17:
				;search for first occurance of a file
	mvi	c,0		;length assuming '?' true
	xchg			;was lhld info
	mov	a,m
	cpi	'?'		;no reselect if ?
	jz	qselect		;skip reselect if so
				;normal search
	call	getexta
	mov	a,m
	cpi	'?'
	cnz	clrmodnum	;module number zeroed
	call	reselect
	mvi	c,namlen
;
qselect:
	call	search
	jmp	dir$to$user	;copy directory entry to user
;
;
func18:				;search for next occurance of filename
	lhld	searcha
	shld	info
	call	reselect
	call	searchn
	jmp	dir$to$user	;copy directory entry to user
;
;
func19:				;delete a file
	call	reselect
	call	delete
	jmp	copy$dirloc
;
;
func20:				;read a file
	call	reselect
	jmp	seqdiskread
;
;
func21:				;write a file
	call	reselect
	jmp	seqdiskwrite
;
;
func22:				;make a file
	call	clrmodnum
	call	reselect
	jmp	make
;
;
func23:				;rename a file
	call	reselect
	call	rename
	jmp	copy$dirloc
;
;
func24:				;return the login vector
	lhld	dlog
	jmp	sthl$ret
;
;
func25:				;return the selected disk number
	lda	curdsk
	jmp	sta$ret
;
;
func26:				;set the subsequent dma address to info
	xchg			;was lhld info
	shld	dmaad		;dmaad = info
	jmp	setdata		;to data dma address
;
;
func27:				;return the login vector address
	lhld	alloca
	jmp	sthl$ret
;
;
func28:	equ	set$ro		;write protect current disk
;
;
func29:				;return r/o bit vector
	lhld	rodsk
	jmp	sthl$ret
;
;
func30:				;set file indicators
	call	reselect
	call	indicators
	jmp	copy$dirloc	;lret = dirloc
;
;
func31:				;return address of disk parameter block
	lhld	dpbaddr
;
sthl$ret:
	shld	aret
	ret
;
;
func32:				;set user code
	lda	linfo
	cpi	0ffh
	jnz	setusrcode	;interrogate user code instead
	lda	usrcode
	jmp	sta$ret		;lret=usrcode
;	ret
;
setusrcode:
	ani	1fh
	sta	usrcode
	ret
;
;
func33:				;random disk read operation
	call	reselect
	jmp	randiskread	;to perform the disk read
;
;
func34:				;random disk write operation
	call	reselect	
	jmp	randiskwrite	;to perform the disk write
;
;
func35:				;return file size
	call	reselect
	jmp	getfilesize
;
;
func36:	equ	setrandom	;set random record
;
;
func37:
	lhld	info
	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
	mov	a,l
	ana	e
	mov	l,a
	mov	a,h
	ana	d
	mov	h,a
	shld	rodsk
	ret
;
;
goback:				;arrive here at end of processing to return
				; to user
	lda	resel
	ora	a
	jz	retmon		;reselection may have taken place
	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	linfo
	call	curselect
;
;	return from the disk monitor
;
retmon:
	lhld	entsp
	sphl			;user stack restored
	lhld	aret
	mov	a,l
	mov	b,h		;ba = hl = aret
	ret
;
func38:	equ	func$ret
func39:	equ	func$ret
;
;
func40:				;random disk write with zero fill of
				; unallocated block
	call	reselect
	mvi	a,2
	sta	seqio
	mvi	c,false
	call	rseek1
	cz	diskwrite	;if seek successful
	ret
;
;
;	data areas
;
;	initialized data
;
efcb:	db	empty		;0e5h=available dir entry
rodsk:	dw	0		;read only disk vector
dlog:	dw	0		;logged in disks
dmaad:	dw	tbuff		;initial dma address
;
;
;	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
buffa:	ds	word		;pointer to directory dma 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	$-buffa		;address list size
;
;	sectpt  -  offset obtained from disk parm block at dpbaddr
;
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
;
tranv:	ds	word		;address of translate vector
;
fcb$copied:
	ds	byte		;set true if copy$fcb called
rmf:	ds	byte		;read mode flag for open$reel
dirloc:	ds	byte		;directory flag in rename, etc.
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
tinfo:	ds	word		;temp for info in 'make'
single:	ds	byte		;set true if single byte allocation map
resel:	ds	byte		;reselection flag
olddsk:	ds	byte		;disk on entry to bdos
fcbdsk:	ds	byte		;disk named in fcb
rcount:	ds	byte		;record count in current fcb
extval:	ds	byte		;extent number and extmsk
vrecord:ds	word		;current virtual record
arecord:ds	word		;current actual record
arecord1:
	ds	word		;current actual block # * blkmsk
;
;	local variables for directory access
;
dptr:	ds	byte		;directory pointer 0, 1, 2, 3
dcnt:	ds	word		;directory counter 0, 1, ... dirmax
drec:	ds	word		;directory record 0, 1, ... dirmax/4
;
bios	equ	($ and 0ff00h)+100h	;next module
	end
