  	.title	'Bdos Interface, Bdos, for DMS'
	.ident HiDos
dvers	==	22h	;version 2.2 (digital research)

version		==	1 ;(digital micro systems)
revision	==	0
mod		==     'l'
patch		==	0
; Last Mod:	March 14,1984	lrw
;________________________________________________
;						_
;	 	" H I D O S "			_
;						_
;	BASIC DISK OPERATING SYSTEM -- BDOS	_		
;						_
;      Digital Microsystem modified CP/M 2.2	_
;						_
;________________________________________________
;
;		TABLE OF CONTENTS		PAGE
;
; 0. History					3
; 1. Assembly time options			6
; 2. Equates
;	low memory equates			7
;	bios access constants			8
;	fcb equates				9
;	other equates				10
; 3. code begin,fixed locations			11
; 4. bdos entry					12
; 5. bdos return routines			13
; 6. bdos functions 1-11 (character i/o)	14
; 7. file functions
;	bdos functions 12-18			16
;	function 19 - delete a file		18
;	function 23 - rename a file		19
;	functions 24-34				20
;	function 35 - file size			23
;	functions 36-40				24
; 8. MPM functions				26
; 9. error messages and routines		28
;10. console routines
;	console handlers			30
;	console read into buffer		34
;11. netlock and unlock,refile,selandlock	38
;12. file routines
;	move to home position,force read	40
;	rdbuff and wrbuff			41
;	seekdir and seek			42
;	dmposition				44
;	index,isitallocated,atran		46
;	getextaddr,getaddrfcb			47
;	getfcb,setfcb,hlrcd,hlrotr		48
;	setcrdisk,nowrite			49
;	setro,checkdirro,checkrofile,checkwrite	50
;	getdptraddr,getmodnum,clrmodnum,setfwflag 51
;	copydir,seekcopy,wrdir,setdata,setdir,dmaset 52
;	dirtouser,endofdir,setenddir		53
;	readdir					54
;	getallocbit,setallocbit,rotr		55
;	setsharedalloc,getsharedalloc		57
;	scandm					59
;	locdircopy				60
;	serch,searchnext			61
;	func15-open,opencopy			65
;	mergezero				67
;	func16-close				68
;	func22-make				71
;	openreel				73
;	seqread,diskread			75
;	func21-diskwrite			76
;	randseek,rand1seek			82
;	rrcompute				85
;	setrandom				86
;	curselect,select,initialize,chkcont	87
;	reselect				91
;13. data area
;	initialized data			92
;	non initialized data			94

.page
.sbttl	'History'

;
;  1/0 = vers/rev
; ================
;
;      mod
;     =====
;	l	17-Mar-84	Les Wilson
;	copy partition name to lockname in lock function
;	rather than select.  minor changes to save space
;	here and there.
;
;      mod
;     =====
;	k	1-Mar-84	Les Wilson
;	changed name and comments back to Hidos
;	from Lidos.  Cleaned up table of contents.
;	no code changes from 1.0j4
;
;      mod
;     =====
;	j	28-Feb-84	Les Wilson
;	put locking into close routine
;
;      mod
;     =====
;	i	22-Feb-84	Les Wilson
;	modified length of bdos to be 0f00h with
;	an extra 100h if mpm locks included instead
;	of 1000h
;
;      mod
;     =====
;	h	16-Feb-84	Les Wilson
;	whenever new block is allocated to shared
;	partition close file.
;	whenever new group is to be allocated for
;	shared partition reopen file to insure
;	latest directory info
;
;      mod
;     =====
;	g	14-Feb-84	Les Wilson
;		partition locking is done on a
;		string composed of the partition
;		name with 5 pluses (+++++) 
;		inserted the middle.
;
;      mod
;     =====
;	f	7-Feb-84	Les Wilson
;		locks are no longer done at highest
;		level possible but where needed. in
;		particular writes are not locked at
;		the highest level.
;
;      mod
;     =====
;	e	1-Feb-84	Les Wilson
;		when selecting shared disk for 
;		first time insure that file
;		containing allocation vector
;		exists.
;
;      mod
;     =====
;	d	26-Jan-84	Les Wilson
;		initialize allocation vector for
;		floppies for creation of new extents.
;		this is to avoid problems since
;		checksums aren`t used.
;
;      mod
;     =====
;	c	9-Jan-84	Les Wilson
;		removed checksums
;		added hashing
;
;      mod
;     =====
;	b	21-Dec-83	Les Wilson
;		modified lock error handling
;		new entries in error handling
;		jump table and table extended to
;		follow hidos identification.
;		three types of errors and actions are:
;		1. Lock table full. issue message and
;			allow retry or abort.
;		2. Partion already locked.  retry 256 
;			times,issue message, allow 
;			retry or abort.
;		3. Partion already unlocked. issue 
;			message and allow continue or
;			abort.
	
;      mod
;     =====
;	a	18-Dec-83	Les Wilson
;		many changes to form of listing,
;		conversion to z80 code
;
;  0/0 = vers/rev
; ================
;
;      mod
;     =====
;	A replaces HidosZ 12/9/83 see that listing for 
;		previous mods and maintanence 
;
;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;
;	Copyright (c) 1978, 1979, 1980
;	Digital Research				
;	Box 579, Pacific Grove
;	California
;
;      20 january 1980
;
; and	Copyright (c) 1983
;	Digital MicroSystems
;	1755 Embarcadero
;	Oakland, California, 94606
;
;
;//////////////////////////////////////////////////////
.page
.sbttl	'Assembly time options'

;
;    BDOS  AND BIOS LOC ADDRESSES
;
bios =\	"Enter the zBios starting address given in
the Bios symbol table ( e.g. 'b400h' ) "
mpmpresent =\ "Enter 0 for MPM lock functions, 1 otherwise "

cpm22len ==	0f00h	;length of cpm portion of bdos
	.ife mpmpresent,[
	mpmlen == 100h	][
	mpmlen == 0 ]

lenBdos	 ==	cpm22len + mpmlen
location ==	bios - lenBdos

	.pabs
	.phex
	.loc	location
	.page
	.sbttl	'low memory equates'
;
;
;	low memory locations
;
reboot	==	0000h	;reboot system
ioloc	==	0003h	;i/o byte location
bdosa	==	0006h	;address field of jmp BDOS
lockStatus ==	49h	;Lock status put here
			;by the BIOS
	;0 = lock or unlock accepted
	;1 = lock request, string exists
	;2 = if lock request, master lock table full
	;	or string length =0 or >13
	;    if unlock request, string not in master
	;	lock table ( i.e. string not locked )
	;	or string length =0 or >13

LOKTABLEFULL == 2	; Lock status for table full.

lockAddress ==	4Ah		;Address of string to
				;use for locking
tfcb	==	005ch	;default fcb location
tbuff	==	0080h	;default buffer location
.page
.sbttl	'bios access equates'
;
;	bios access constants
bootf	==	bios+3*0 ;cold boot function
wbootf	==	bios+3*1 ;warm boot function
constf	==	bios+3*2 ;console status function
coninf	==	bios+3*3 ;console input function
conoutf	==	bios+3*4 ;console output function
listf	==	bios+3*5 ;list output function
punchf	==	bios+3*6 ;punch output function
readerf	==	bios+3*7 ;reader input function
homef	==	bios+3*8 ;disk home function
seldskf	==	bios+3*9 ;select disk function
settrkf	==	bios+3*10 ;set track function
setsecf	==	bios+3*11 ;set sector function
setdmaf	==	bios+3*12 ;set dma function
readf	==	bios+3*13 ;read disk function
writef	==	bios+3*14 ;write disk function
liststf	==	bios+3*15 ;list status function
sectran	==	bios+3*16 ;sector translate
;
;	Non standard BIOS routine access constants
;
lockF	==	bios + 60h ;network lock
unLockF	==	bios + 66h ;network unlock
setNetModeF ==	bios + 8Ah
locktries ==	512	;number of attempts to lock
		;partition before giving up and asking
		;user to ignore
;	Set mode for net read buffer use.
;	Only for net station, not for master.
;	Pass in reg C:
;		0 = use normal net buffering
;		1 = Do NOT use buffer THIS TIME
;		2 = never use net read buffer
;
NotThisTime	== 1 ; Used for setNetModeF above.
	.page
	.sbttl	'fcb equates'
;
;	file control block (fcb) constants
;
empty	==	0e5h	;empty directory entry
lstrec	==	127	;last record# in extent
recsiz	==	128	;record size
fcblen	==	32	;file control block size
dirrec	==	recsiz/fcblen ;directory entrys
			;per record
dskshf	==	2	;log2(dirrec)
dskmsk	==	dirrec-1
fcbshf	==	5	;log2(fcblen)
;
extnum	==	12	;extent number field
maxext	==	31	;largest extent number
ubytes	==	13	;unfilled bytes field
modnum	==	14	;data module number
maxmod	==	63	;largest module number,
		;32 megabyte file size supported
fwfmsk	==	80h	;file write flag is high 
			;order modnum
namlen	==	15	;name length
reccnt	==	15	;record count field
dskmap	==	16	;disk map field
lstfcb	==	fcblen-1
nxtrec	==	fcblen
ranrec	==	nxtrec+1;random record field (2 bytes)
;
;	reserved file indicators
rofile	==	9	;high order of first type char
invis	==	10	;invisible file in dir command
;	==	11	;reserved
.page
.sbttl	'other equates'
;
;	MPM record locking parameters
namelen  ==	11	;name plus type
nameonlylen == 8	;name of file only
locklen ==	13	;namelen plus record #
r0off	==	33	;offset of record #
r2off	==	35	;record # MSB offset
;
prtnmlen ==	8	;length of partion name
lenprtnminsert == 5	;length of +'s inserted
			;in partition name for
			;locking
;
;
;	equates for non graphic characters
ctlc	==	03h	;control c
ctle	==	05h	;physical eol
ctlh	==	08h	;backspace
ctlp	==	10h	;prnt toggle
ctlr	==	12h	;repeat line
ctls	==	13h	;stop/start screen
ctlu	==	15h	;line delete
ctlx	==	18h	;=ctl-u
ctlz	==	1ah	;end of file
rubout	==	7fh	;char delete
tab	==	09h	;tab char
cr	==	0dh	;carriage return
lf	==	0ah	;line feed
ctl	==	5eh	;up arrow
questionmark == 3fh	;guess

;
;	constants labelling bits/flags
;
FLGshared	== 6 ; Bit 6 of control byte
		;indicates a shared
		;drive
NOTFLOPPY	== 40h ; Bit 6 of media byte of
		;DPB is not used by floppy disks
DMSDPBoffset	== 16	;DPB-16 is beginning of 
		;DMS dpb, i.e. the control byte.
;
;	literal constants
true	==	0ffh	;constant true
false	==	000h	;constant false
enddir	==	0ffffh	;end of directory
byte	==	1	;number of bytes for "byte" type
word	==	2	;number of bytes for "word" type
	.page
	.sbttl	'code begin,fixed locations'
;	########################################
;	###				     ###
;	### relative locations 0000h - 001Dh ###
;	### MUST be kept at these locations  ###
;	### relative to BDOS loc address.    ###
;	###				     ###
;	########################################
;
;   ++++++++++	B E G I N    C O D E  ++++++++++
;
	.byte	0,0,0,0,0,0
;
;	enter here from the user's program with 
;	function number in c,
;	and information address in d,e
;
; !!!! KEEP THIS A "JMP" NOT A "JMPR" !!!!
;
	jmp	BdosEntry	;past variables/data
;
;	this error jump table is to allow applications
;	to do there own handling of errors if they
;	so desire.  all bdos error handling MUST go
;	thru this table
;
PerErr:	.word	PerSub	;permanent (read/write)
			;error subroutine
SelErr:	.word	SelSub	;select error subroutine
RodErr:	.word	RodSub	;ro disk error subroutine
RofErr:	.word	RofSub	;ro file error subroutine
LokfErr: .word	LokfSub	;Lock table full in NetLock
nlokerr:.word	nloksub	;was not locked in netunlock
;
;	BDOS IDENTIFICATION BYTES
;  At bdos loc + 21 decimal
;  These bytes are for use of utilities such as assign
ident:	.ascii	'HIDOS'
	.ascii	[version+30h][revision+30h][mod]
;
;	contination of error jump table
;
lokerr:	.word	loksub	;256 attempts to lock partition
			;failed
sharerr:.word	sharesub ;no directory entry for shared
		;partitions alloc vector present
;
;	###########################################
;	###					###
;	###	end relative restriction	###
;	###					###
;	###########################################
	.page
	.sbttl	'bdos entry'
;
BdosEntry:	;arrive here from user programs
	sded	info	;info=DE, DE=info
	mov	a,e
	sta	linfo	;linfo = low(info) - don't ==
	lxi	h,0
	shld	aret 	;return value defaults to 0000
	shld	resel	;resel,fcbdsk = false
    ;save user's stack pointer, set to local stack
	sspd	entsp 		;entsp = stackptr
	lxi	sp,lstack	;local stack setup

	lxi	h,goback 	
	push	h		; jmp goback == 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=.ciotab
	dad	d
	dad	d
	mov	e,m
	inx	h
	mov	d,m		;DE=functab(func)
	lhld	info	;info in DE for later xchg	
	xchg
	pchl 		;dispatched
.page
.sbttl	'bdos return routines'
GoBack:
    ;arrive here at end of processing to return to user
	lda	resel
	ora	a
	jrz	RetMon

    ;reselection may have taken place
	lhld	info
	mvi	m,0		;fcb(0)=0
	lda	fcbdsk
	ora	a
	jrz	RetMon

    ;restore disk number
	mov	m,a		;fcb(0)=fcbdsk
	lda	olddsk
	sta	linfo
	call	CurSelect
;
;...........................
;
;	return from the disk monitor
RetMon:
	lspd	entsp	;user stack restored
	lhld	aret
	mov	a,l
	mov	b,h		;BA = HL = aret
	ret
.page
.sbttl	'bdos functions 1-11 (character i/o)'
;
;return console character with echo
;
Func1:
	call	ConEch
	jmpr	StAret

;
;write console character with tab expansion
;
;Func2	==	TabOut

;
;return reader character
;
Func3:
	call	readerf
	jmpr	StAret

;
;Func4:	equated to punchf    ;write punch character
;

;
;Func5:	equated to listf
;write list character
;write to list device
;

;
;direct console i/o - read if 0ffh,status if 0feh
;
Func6:
	mov	a,c
	inr	a
	jrz	..dirinp ;0ffh=>00h, means input mode
	inr a
	jrnz	..dirout
	call	constf	;0feH in C for status
	jmpr	staret	; direct output function
..dirout:
	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
	jmpr	StAret

;
;return io byte
;
Func7:
	lda	ioloc
	jmpr	StAret

;
;set i/o byte
;
Func8:
	lxi	h,ioloc
	mov	m,c
	ret		;jmp goback

;
;	write line until $ encountered
;	print message until M(DE) = '$'
;
Func9:
Print:
	ldax	d
	cpi	'$'
	rz		; stop on $

; more to print
	inx	d
	push	d
	mov	c,a	;char to C
	call	TabOut	;another character printed
	pop	d
	jmpr	Print

;
;read a buffered console line
;
;Func10	==	Read

;
;check console status
;
Func11:
	call	ConBrk	;(drop through to staret)
StAret:    ;store the A register to aret
	sta	aret
FuncRet:
	ret 	; jmp goback 
		; (pop stack for non cp/m functions)

;
;set lret = 1
;
SetLret1:
	mvi	a,1
	jmpr	StAret
.page
.sbttl	'functions 12-18'
;
;	individual function handlers
;

;
;return version number
;
Func12:
	mvi	a,dvers
	jmp	StAret	;lret = dvers (high = 00)

;
;reset disk system - initialize to disk 0
;
Func13:
	lxi	h,0
	shld	rodsk
	shld	dlog
	xra	a
	sta	curdsk		;note that usrcode 
				;remains unchanged
	lxi	h,tbuff
	shld	dmaad		;dmaad = tbuff
      	call	SetData		;to data dma address
	jmp	Select

;
;select disk info
;
;Func14	==	CurSelect

;
;search for first occurrence of a file
;
Func17:
	mvi	c,0 ;length assuming questionmark true
	xchg		;was lhld info		
	mov	a,m
	cpi	questionmark	;no reselect if so
	jrz	..qselect	;skip reselect if so

;normal search
	call	GetExtAddr
	mov	a,m
	cpi	questionmark
	cnz	ClrModNum	;module number zeroed
	call	ReSelect
	mvi	c,namlen

..qselect:
	call	Serch
	jmp	DirToUser ;copy directory entry to user

;
;search for next occurrence of a file name
;
Func18:
	lhld	adrSearch
	shld	info
	call	ReSelect
	call	SearchNext
	jmp	DirToUser ;copy directory entry to user
.page
.sbttl	'function 19 - delete a file'
;
;delete a file
;
Func19:
	call	selandlock
	mvi	c,extnum
	call	Serch	;search through file type

	inr	a	;turn 0ffh(failure) to zero
	jrz	..out		; return if not found
;
;	if shared partition read in allocation vector
;
	call	chkcont
	jrz	..del0
	call GetSharedAlloc ;If shared,get shared alloc
	call	Seekdir	; Reset track and sector 
			;to the directory as set
			;by Serch above, so call to
			;WrDir below will be OK.

;loop while directory matches
..del0:

;set each non zero disk map entry to 0
;in the allocation vector
;may be r/o file
	call	CheckDirRo	;ro disk error if found
	call	GetDptrAddr	;HL=.buff(dptr)
	mvi	m,empty
	mvi	c,0
	call	ScanDM		;alloc elts set to 0
	call	WrDir		;write the directory
	call	SearchNext	;to next element
	inr	a
	jrnz	..del0		;for another record
	call	chkcont
	cnz	SetSharedAlloc  ; write if shared
..out:
	call	LocDirCopy
	jmp	NetUnLock
.page
.sbttl	'function 23 - rename a file'
;
;rename a file
;
Func23:
	call	selandlock
;
;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
;
;search up to the extent field
	mvi	c,extnum
	call	Serch
;copy position 0
	lhld	info
	mov	b,m		;HL=.fcb(0), A=fcb(0)
	lxi	d,dskmap
	dad	d		;HL=.fcb(dskmap)
	mov	m,b		;fcb(dskmap)=fcb(0)
;assume the same disk drive for new named file
..rename0:
	inr	a	
	jrz	..enddir	;stop at end of dir
;not end of directory, rename next element
	call	CheckDirRo  ;may be read-only file
	mvi	c,dskmap
	mvi	e,extnum
	call	CopyDir
;element renamed, move to next
	call	SearchNext
	jmpr	..rename0
..enddir:
	jmp	NetUnLock
.page
.sbttl	'functions 24-34'
;
;return the login vector
;
Func24:
	lhld	dlog
	jmpr	StHLret

;
;return selected disk number
;
Func25:
	lda	curdsk
	jmp	StAret

;
;set the subsequent dma address to info
;
Func26:
	sded	dmaad		;dmaad = info
	jmp	SetData		;to data dma address

;
; Return the allocation vector address
; If shared drive force read of alloc vector
;
Func27:
	call 	chkcont
	jrz	..1	; if not shared skip read
	call	GetSharedAlloc
..1:
	lhld	alloca
	jmpr	StHLret

;
;write protect current disk
;
;Func28	==	SetRO

;
;return r/o bit vector
;
Func29:
	lhld	rodsk
	jmpr	StHLret

;
;set file indicators for current fcb
;
Func30:
	call	ReFile
	mvi	c,extnum
	call	Serch		;through file type
..indic0:
	inr	a
	jrz	..enddir	;stop at end of dir

;not end of directory, continue to change
	mvi	c,0
	mvi	e,extnum		;copy name
	call	CopyDir
	call	SearchNext
	jmpr	..indic0
..enddir:
	call	LocDirCopy	;lret=dirloc
	jmp	NetUnLock

;
;return address of disk parameter block
;
Func31:
	lhld	dpbaddr
;
;.....................
;
StHLret:
	shld	aret
	ret

;
;set or interogate user code
;
Func32:
	lda	linfo
	cpi	0ffh
	jrnz	..setusrcode

;interrogate user code instead
	lda	usrcode
	jmp	StAret		;lret=usrcode	

..setusrcode:
	ani	1fh
	sta	usrcode
	ret

;
;random disk read operation
;
Func33:
	call	ReSelect
	mvi	c,true	;marked as read operation
	call	RandSeek
	cz	DiskRead	;if seek successful
	ret

;
;random disk write operation
;
Func34:
	call	Reselect
	mvi	c,false	 ;marked as write operation
	call	RandSeek
	cz	DiskWrite	;if seek successful
	ret
.page
.sbttl	'function 35 - file size'
;
;return file size (0-65536)
;
Func35:
	call	ReSelect
	mvi	c,extnum
	call	Serch
;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:
	inr	a
	jrz	..setsize
;current fcb addressed by dptr
	call	GetDptrAddr
	lxi	d,reccnt	;ready for compute size
	call	RRcompute
;A=0000 000X 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
	jrc	..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	SearchNext
	jmpr	..getsize

..setsize:
	pop	h		;discard .fcb(ranrec)
	ret
.page
.sbttl	'functions 36-40'
;
;set random record
;
;Func36	==	SetRandom

;
;Need to select disk after call so that
;if disk being reset is to be accessed
;by a call that does not check if the
;disk is logged in (e.g. reads/writes)
;the disk will already be logged in.
;
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

;
;not implemented
;
Func38	==	FuncRet

;
;not implemented
;
Func39	==	FuncRet

;
;random disk write with zero fill of unallocated blk
;
Func40:
	call	Reselect
	mvi	a,2
	sta	seqio
	mvi	c,false
	call	Rand1Seek
	cz	DiskWrite	;if seek successful
	ret
.page
.sbttl	'MPM functions'
.ife	mpmpresent,[
;
;not implemented
;
Func41	==	FuncRet

;
; MPM record lock function
;
Func42:
	call	lockset
	call	lockf
	lda	lockstatus
	ora	a
	jrz	exit
	cpi	loktablefull
	jrnz	..recl1
	mvi	a,0eh	;no room in lock table
	jmpr	exit
..recl1:
	mvi	a,8	;record already locked
	jmpr	exit

;
	; MPM record unlock function
;
Func43:
	call	lockset
	call	unlockf
	xra	a	;no bad status
	jmpr	exit

;
;	common routines for func 42, 43
;
rangerr:
	mvi	a,6	;out of range err
	pop	h	;restore stack
exit:	jmp	STAret	;return with status in A
;
getoff:	lhld	info	;HL=HL+DE
	dad	d	;A=(HL)
	mov	a,m
	ret
;
lockset:
	lxi	d,r2off	;test MSB of record #
	call	getoff  ; for out of range rec #
	ora	a
	jnz	rangerr
	lhld	info
	inx	h	;point to name in FCB
	lxi	d,lockname+1
	lxi	b,namelen
	ldir		;move name and type
	lxi	d,r0off
	call	getoff
	mov	a,m
	sta	rec0	;move LSB of record #
	inx	h
	mov	a,m
	sta	rec1	;move second byte 
	lxi	h,lockname
	mvi	m,locklen
	shld	lockaddress
	ret
	]	;end of MPM functions
.page
.sbttl 'error messages and routines'
;
;	error messages
;
dskmsg:	.ascii	'Bdos Err On '
dskerr:	.ascii	' : $'		;filled in by errflg
permsg:	.ascii	'Bad Sector$'
selmsg:	.ascii	'Select$'
rofmsg:	.ascii	'File '
rodmsg:	.ascii	'R/O$'
nlokmsg:.ascii	' Not'
lokmsg:	.ascii	' Locked$'
lokfmsg:.ascii	'No Locks$'
sharemsg:.ascii	' SHRALLOC$'
;

;
;	error subroutines
;
sharesub:		;report that shralloc not
	lxi	d,sharemsg ;run on shared partition
	call	print
	jmp	reboot

PerSub:			; Report permanent error
	lxi	h,permsg
userChoice:
	call	ErrFlg		;to report the error
actonuserchoice:
	cpi	ctlc
	jz	reboot 	; reboot if response is ctlc
	ret 		; else ignore the error
;
;
lokfsub:	;report lock table full
	lxi	h,lokfmsg
	jmpr	userchoice
;
;
LokSub:			; Report lockup from NetLock
	lxi	H,lokmsg
prnlock:	;print partition which is locked
	push	h
	call	crlf
	lxi	h,lockname+prtnmlen+lenprtnminsert+1
	mvi	m,'$'	;point past partion name
	lxi	d,lockname+1
	call	print
	pop	d
	call	print
	call	conin
	jmpr	actonuserchoice
;
;
nloksub:	;report unlocked status from netunlock
	lxi	h,nlokmsg
	jmpr	prnlock
;
;
SelSub:			; Report select error
	lxi	h,selmsg
	jmpr	WaitErr	; wait console before boot
;
;
RodSub:	;report write to read/only disk
	lxi	h,rodmsg
	jmpr	waiterr	; wait console
;
;
RofSub:	;report read/only file
	lxi	h,rofmsg 	;drop through to wait
;
;
WaitErr:
	;wait for response before boot
	call	ErrFlg
	jmp	reboot
;
;
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	d,dskmsg
	call	Print	;the error message
	pop	d
	call	Print	;error mssage tail
    		;(drop through to ConIn)
;
	.page
	.sbttl	'console handlers'
;
;	read console character to A
;
ConIn:		;( possible drop through from ErrFlg )
	lxi	h,kbchar
	mov	a,m
	mvi	m,0
	ora	a
	rnz
;no previous keyboard character ready
	jmp	coninf	;get character externally

;
;	read character with echo
;
ConEch:
	call	ConIn
	call	EchoChar
	rc		;echo character
;character must be echoed before return
	push	psw
	mov	c,a
	call	TabOut
	pop	psw
	ret		;with character in A

;
;	echo character if graphic
;	cr, lf, tab, or backspace
;
EchoChar:
	cpi	cr
	rz		;carriage return
	cpi	lf
	rz		;line feed
	cpi	tab
	rz		;tab
	cpi	ctlh
	rz		;backspace
	cpi	' '
	ret		;carry set if not graphic

;
;    check for character ready
;
ConBrk:
	lda	kbchar
	ora	a
	jrnz	..1conbrk	;skip if active kbchar

;no active kbchar, check external break
	call	constf
	ani	1
	rz		;return if no char ready

;character ready, read it
	call	coninf	;to A
	cpi	ctls
	jrnz	..0conbrk ;check stop screen function

;found ctls, read next character
	call	coninf	;to A
	cpi	ctlc
	jz	reboot	;ctlc implies re-boot

;not a reboot, act as if nothing happened
	xra	a
	ret		;with zero in accumulator

..0conbrk:		;character in accum, save it
	sta kbchar
..1conbrk:	;return with true set in accumulator
	mvi a,1
	ret

;
;carriage return line feed sequence
;
CrLf:
	mvi	c,cr
	call	ConsoleOut
	mvi	c,lf

;
;compute char pos/write console char from C
;compcol = true if computing column position
;
ConsoleOut:
	lda	compcol
	ora	a
	jrnz	..CompOut

;write the character, then compute 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 the character
..CompOut:
	mov	a,c	;recall the character
			;and compute column position
	lxi	h,column ;A = char, HL = .column
	cpi	rubout
	rz		;no column change if nulls
	inr	m	;column = column + 1
	cpi	' '
	rnc		;return if graphic
			;not graphic, reset column pos
	dcr	m	;column = column - 1
	mov	a,m
	ora	a
	rz		;return if at zero
			;else backspace or end line
	mov	a,c	;character back to A
	cpi	ctlh
	jrnz	..notbacksp

		    ;backspace character
	dcr	m	;column = column - 1
	ret

..notbacksp:
		    ;not a backspace character, eol
	cpi	lf
	rnz		;return if not

		    ;end of line, column = 0
	mvi	m,0	;column = 0
	ret

;
;send C character with possible preceding up-arrow
;
CtlOut:
	mov	a,c
	call	EchoChar ;cy if not graphic or special 
	jrnc	TabOut	
;skip if graphic, tab, cr, lf, or ctlh
;send preceding up arrow
	push	psw
	mvi	c,ctl
	call	ConsoleOut	;up arrow
	pop	psw
	ori	40h	;becomes graphic letter
	mov	c,a	;ready to print
	    ;(drop through to tabout)

;
;expand tabs to console, send other characters along
;
TabOut:
	mov	a,c
	cpi	tab
	jrnz	ConsoleOut	;direct to conout if not

;tab encountered, move to next tab position
..tab0:
	mvi	c,' '
	call	ConsoleOut	;another blank
	lda	column
	ani	111b	;column mod 8 = 0 
	jrnz	..tab0	;back for another if not
	ret

;
;back-up one screen position
;
Backup:
	call	PctlH
	mvi	c,' '
	call	conoutf
    ;(drop through to pctlh)
;
;send ctlh to console without affecting column count
;
PctlH:
	mvi	c,ctlh
	jmp	conoutf

;
;print #, cr, lf for ctlx, ctlu, ctlr functions
;then move to strtcol (starting column)
;
CrLfP:
	mvi	c,'#'
	call	ConsoleOut
	call	CrLf

;column = 0, move to position strtcol
..0crlfp:
	lda	column
	lxi	h,strtcol
	cmp	m
	rnc	;stop when column reaches strtcol

	mvi	c,' '
	call	ConsoleOut	;print blank
	jmpr	..0crlfp

.page
.sbttl	'console read into buffer'
;
;read to info address 
; (max length, current length, buffer)
;
Read:
	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
;read next character, BC, HL active
..nxread:
	push	b
	push	h	;blen, cmax, HL saved
..0nread:
	call	ConIn	;next char in A
	ani	7fh	;mask parity bit
	pop	h
	pop	b	;reactivate counters
	cpi	cr
	jz	..endread	;end of line
	cpi	lf
	jz	..endread	;also end of line
	cpi	ctlh
	jrnz	..noth	;backspace

;do we have any characters to back over
	mov	a,b
	ora	a
	jrz	..nxread

;characters remain in buffer, backup one
	dcr	b	;remove one character
	lda	column
	sta	compcol	;col > 0
;compcol > 0 marks repeat as length compute
	jmpr	..linelen  ;uses same code as repeat

..noth:		    ;not a backspace
	cpi	rubout
	jrnz	..ntrub		;rubout char

;rubout encountered, rubout if possible
	mov	a,b
	ora	a
	jrz	..nxread	;skip if len=0

;buffer has characters, resend last char
	mov	a,m
	dcr	b
	dcx	h	;A = last char
;blen=blen-1, next to fill - 1 decremented
	jmpr	..1rdech  ;act like this is an echo

..ntrub:    ;not a rubout character, check end line
	cpi	ctle
	jrnz	..note	;physical end line

;yes, save active counters and force eol
	push	b
	push	h
	call	crlf
	xra	a
	sta	strtcol	;start position = 00
	jmpr	..0nread	;for another character

..note:	    ;not end of line, list toggle
	cpi	ctlp
	jrnz	..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-listcp
	mov	m,a	;listcp = not listcp
	pop	h
	jmpr	..nxread	;for another char

..notp:	    ;not a ctlp, line delete
	cpi	ctlx
	jrnz	..notx
	pop	h	;discard start position

;loop while column > strtcol
..xback:
	lda	strtcol
	lxi	h,column
	cmp	m
	jrnc	Read	;start again
	dcr	m	;column = column - 1
	call	Backup	;one position
	jmpr	..xback

..notx:	    ;not control-X, control-U
	cpi	ctlu
	jrnz	..notu	;skip if not

;delete line (ctlu)
	call	CrLfP	;physical eol
	pop	h	;discard starting position
	jmpr	Read	;to start all over

..notu:	    ;not line delete, repeat line
	cpi	ctlr
	jrnz	..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
	jrz	..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
	jmpr	..rep0	;for the next character

;end of repeat, recall lengths
;original BC still remains pushed
..rep1:
	push	h	;save next to fill
	lda	compcol
	ora	a	;>0 if computing length
	jz	..0nread ;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

..spback:	    ;move back one more space
	call	Backup	;one space
	lxi	h,compcol
	dcr	m
	jrnz	..spback
	jmp	..0nread	;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

..1rdech:    ;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
	jrnz	..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	..nxread	;go for another if not

..endread:    ;end of read operation, store blen
	pop	h
	mov	m,b	;M(current len) = B
	mvi	c,cr
	jmp	ConsoleOut ;return carriage
.page
.sbttl	'netlock and unlock,refile,selandlock'
ReFile:	call	ReSelect ;then fall into netlock	

NetLock:
	call chkcont ;check if partiton is shared.
	rz		; Not shared so do not lock.
; Load lockName with the partition name from
;the current disks' DPB. insert 5 pluses in the
;middle
	lxi H,diskName ;local copy of partition name
	lxi	D,lockName+1	;First byte of lockName
				; = length of name (8)
	lxi	B,prtnmlen/2	; Transfer 4 byte name
	ldir			; Do the transfer
	mov	h,d
	mov	l,e
	mvi	m,'+'	;move first plus in
	inx	d
	lxi	 b,lenprtnminsert-1
	ldir		;copy rest of pluses in
	lxi	h,diskname + (prtnmlen/2)
	lxi	b,prtnmlen/2
	ldir	;copy rest of partition name in

; Set lockAddress to contain lockName's address.
; In Select the partition name is put at lockName.
	lxi	H,lockName
	shld	lockAddress
	mvi	M,prtnmlen + lenprtnminsert ;length
			;of hidos lockname
	lxi	h,locktries
	shld	lockcount ;count of times to go
			;thru lockloop
..lockLoop:
	call	LockF		; Is shared, so lock.
	lda	lockStatus
	cpi	LOKTABLEFULL	; = 2; Lock table full
	cz	..lckfull	;Call lock table full
				;error routine
	lda	lockStatus ;LokSub might have trashed A
	ora	A	; Set zero flag on reg A
	rz
	lhld	lockcount
	dcx	h
	shld	lockcount
	mov	a,h
	ora	l
	jrnz	..lockloop
	call	..islocked
	lxi	h,locktries
	shld	lockcount	;give it some more
	jmpr	..lockloop	;tries

..islocked:
	lhld	lokerr
	pchl		;return from there

..lckfull:
	lhld	lokferr
	pchl		;return from ther


NetUnLock:		; lockAddress set in Select
	call chkcont	;check if partiton is shared.
	rz		; Not shared so do not unlock.
..unlockLoop:
	call	UnlockF		; Is shared, so unlock.
	lda	lockStatus
	ora	A	   ; Set zero flag on reg A
	rz
	lhld	nlokerr
	pchl		;return from there

;
;	common code to select, check for readonly and
;	lock the partition
;
selandlock:
	call	reselect
	call	checkwrite
	jmp	netlock
.page
.sbttl	'move to home position,force read'
;
;move to home position
;
Home:
	call	homef		; move to track 00, 
				;sector 00 reference

	xra	a	;constant zero to accumulator
	lhld	curtrka
	mov	m,a
	inx	h
	mov	m,a		;curtrk=0000
	inx	h		; HL = curreca,NOTE:
			;this is based on currec,curtrk 
			;being contiguous
; 	lhld	curreca	;this would always work

	mov	m,a
	inx	h
	mov	m,a		;currec=0000

; If shared force read from disk, don't read from
;net read buffer.
forceread:
	call	chkcont
	rz		; return if not shared
	mvi	C,NotThisTime	; Don't use net read
				;buffer this time.
	jmp	setNetModeF	; Set net buffer mode
.page
.sbttl 'rdbuff and wrbuff'
;
;read buffer and check condition
;
RdBuff:
	call	readf	;current drive, track, 
			;sector, dma
	jmpr	diocomp	;check for i/o errors

;
;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
;
WrBuff:
	call	writef	;current drive, track,
			;sector, dma
;
;.....................
;
DioComp:		;check for disk errors
	ora	a
	rz
	lhld	PerErr
	pchl
.page
.sbttl	'seekdir and seek'
;
;seek the record containing the current dir entry
;
SeekDir:
	lhld	dcnt	;directory counter to HL
	mvi	c,dskshf
	call	HLrotR		;value to HL
	shld	arecord
	shld	drec		;ready for seek
;
;seek the track given by arecord (actual record)
;local equates for registers
	arech  == b
	arecl  == c		;arecord = BC
	crech  == d
	crecl  == e		;currec  = DE
	ctrkh  == h
	ctrkl  == l		;curtrk  = HL
	tcrech == h
	tcrecl == l		;tcurrec = HL
;
Seek:		;load the registers from memory
	lbcd	arecord
	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
..0seek:
	mov	a,arecl
	sub	crecl
	mov	a,arech
	sbb	crech
	jrnc	..1seek ;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
	jmpr	..0seek	;for another try

;look while arecord >= (t:=currec + sectpt)
..1seek:
	push	ctrkh
	lhld	sectpt
	dad	crech	 ;HL = currec+sectpt
	jrc	..2seek		;can be > FFFFH	
	mov	a,arecl
	sub	tcrecl
	mov	a,arech
	sbb	tcrech
	jrc	..2seek		;skip if t > arecord
;currec = t
	xchg
;curtrk = curtrk + 1
	pop	ctrkh
	inx	ctrkh
	jmpr	..1seek		;for another try
..2seek:
	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
	lded	tranv		;BC=sector#, DE=.tran
	call	sectran		;HL = tran(sector)
	mov	c,l
	mov	b,h		;BC = tran(sector)
	jmp	setsecf		;sector selected
	.page
	.sbttl	'dmposition'
;
;compute disk map position for vrecord to HL
;
DMposition:
	lxi h,blkshf
	mov	c,m	;shift count to C
	lda	vrecord	;current virtual record to A
..0dmpos:
	srlr	a
	dcr	c
	jrnz	..0dmpos
;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

;blkshf = 3,4,5,6,7, C=5,4,3,2,1
;shift is 4,3,2,1,0
..1dmpos:
	dcr	c
	jrz	..2dmpos
	slar	a
	jmpr	..1dmpos

;arrive here with A = shl(ext and extmsk,7-blkshf)
..2dmpos:
	add b ;add previous shr(vrecord,blkshf) value
	ret	;with dmposition in A
;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

;
;return disk map value from position given by BC
;
GetDM:
	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
	jrz	..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
.page
.sbttl	'index,isitallocated,atran'
;
;compute disk block number from current fcb
;
Index:
	call	DMposition	;0...15 in register A
	mov	c,a
	mvi	b,0
	call	GetDM		;value to HL
	shld	arecord
	ret

;
;called following index to see if block allocated
;
IsItAllocated:
	call	index
	lhld	arecord
	mov	a,l
	ora	h
	ret

;
;compute actual record address, assuming index called
;
Atran:
	lda	blkshf		;shift count to reg A
	lhld	arecord
..atran0:
	dad	h
	dcr	a
	jrnz	..atran0	;shl(arecord,blkshf)

	shld	a1record	;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
.page
.sbttl	'getextaddr,getaddrfcb'
;
;get current extent field address to A
;
GetExtAddr:
	lhld	info
	lxi	d,extnum
	dad	d		;HL=.fcb(extnum)
	ret

;
;compute reccnt and nxtrec addresses for get/setfcb
;
GetAdrFcb:
	lhld	info
	lxi	d,reccnt
	dad	d
	xchg			;DE=.fcb(reccnt)
	lxi	h,(nxtrec-reccnt)
	dad	d		;HL=.fcb(nxtrec)
	ret
.page
.sbttl	'getfcb,setfcb,hlrcd,hlrotr'
;
;set variables from currently addressed fcb
;
GetFcb:
	call	getAdrFcb	;addresses in DE, HL
	mov	a,m
	sta	vrecord		;vrecord=fcb(nxtrec)
	xchg
	mov	a,m
	sta	rcount		;rcount=fcb(reccnt)
	call	GetExtAddr 	;HL=.fcb(extnum)
	lda	extmsk 		;extent mask to a
	ana	m 		;fcb(extnum) and extmsk
	sta	extval
	ret

;
;place values back into current fcb
;
SetFcb:
	call	getAdrFcb	;addresses to DE, HL
	lda	seqio
	cpi	02
	jrnz	..setfcb1
	xra	a		;check ranfill	
..setfcb1:
	mov 	c,a 	;=1 if squential i/o
	lda	vrecord
	add	c
	mov	m,a	;fcb(nxtrec)=vrecord+seqio
	xchg
	lda	rcount
	mov	m,a		;fcb(reccnt)=rcount
	ret

;
;shift hl right by current disk
;
HLRcd:
	lda	curdsk
	mov	c,a
;
; shift HL right by amount C
;
HLrotR:
	inr c		;in case zero
..hlrotr0:
	dcr	c
	rz		;return when zero

	srlr	H
	rarr	L
	jmpr	..hlrotr0

.page
.sbttl	'setcrdisk,nowrite'

;
;set a "1" value in curdsk position of BC
;
SetCrDisk:
	lda	curdsk
	lxi	h,1		;number to shift
;HL = mask to integrate
;shilf left the mask in HL by amount in a
	inr	a		;may be zero
..hlrotl0:
	dcr	a
	jrz	..cont	;return if zero
	dad 	h
	jmpr	..hlrotl0
..cont:	mov	a,c
	ora	l
	mov	l,a
	mov	a,b
	ora	h
	mov	h,a	;HL = mask or rol(1,curdsk)
	ret

;
;return true if disk read only
;
NoWrite:
	lhld	rodsk
	call	HLRcd
	mov	a,l
	ani	1b
	ret		;non zero if nowrite
.page
.sbttl	'setro,checkdirro,checkrofile,checkwrite'
;
;set current disk to read only
;
SetRO:
	lxi	h,rodsk
	mov	c,m
	inx	h
	mov	b,m
	call	SetCrDisk	;sets bit to 1
	shld	rodsk
	ret

;
;check current directory element for read/only status
;
CheckDirRo:
	call	GetDptrAddr	;address of element
;						
;..................
;check current buff(dptr) or fcb(0) for r/o status
;
CheckRoFile:
	lxi	d,rofile
	dad	d		;offset to ro bit
	mov	a,m
	ral
	rnc			;return if not set
	lhld	roferr 	;exit to read only disk message
	pchl

;
;check for write protected disk
;
CheckWrite:
	call	NoWrite
	rz		;ok to write if not rodsk
	lhld	roderr	;read only disk error
	pchl
.page
.sbttl	'getdptraddr,getmodnum,clrmodnum,setfwflag'
;
;compute the address of a directory element at
;positon dptr in the buffer
;
GetDptrAddr:
	lhld	buffa
	lda	dptr
;
;......................
;HL = HL + A
;
addh:
	add	l
	mov	l,a
	rnc
;overflow to H
	inr	h
	ret

;
;compute the address of the module number 
;bring module number to accumulator
;(high order bit is fwf (file write flag)
;	reg out:
;	a - modnumber
;	h - address of modnumber
;
GetModNum:
	lhld	info
	lxi	d,modnum
	dad	d		;HL=.fcb(modnum)
	mov	a,m
	ret			;A=fcb(modnum)

;
;clear the module number field for user open/make
;
ClrModNum:
	call	GetModNum
	mvi	m,0		;fcb(modnum)=0
	ret

;
;set fwf (file write flag) to "1"
;also returns non zero in accumulator
;
SetFWflag:
	call GetModNum ;HL=.fcb(modnum), A=fcb(modnum)
	ori	fwfmsk
	mov	m,a	;fcb(modnum)=fcb(modnum) or 80h
	ret
.page
.sbttl	'copydir,seekcopy,wrdir,setdata,setdir,dmaset'
;
;copy fcb information starting at C for E bytes
;into the currently addressed directory entry
;
CopyDir:
	push	d		;save length for later
	mvi	b,0		;double index to BC
	lhld	info		;HL = source for data
	dad	b
	push	h	;HL =.fcb(C), source for copy
	call	GetDptrAddr	;HL=.buff(dptr), dest
	pop	d
	xchg
	pop	b	;HL=source, de=dest, C=length
	mvi	b,0
	ldir		;data moved
;
;........................
;enter from close to seek and copy current element
;
SeekCopy:
	call	SeekDir	;to the directory element
;	fall thru to WrDir
;........................
;
;write the current directory entry
;
WrDir:
	call	SetDir		;directory dma
	mvi c,1 ;indicates a write directory operation
	call	WrBuff		;write the buffer

;
;.....................
;set data dma address
SetData:
	lbcd	dmaad
	jmpr	DmaSet		;to complete the call
;
;set directory dma address
;
SetDir:
	lbcd	buffa 	;jmp DmaSet to complete call     
;
;........................
;
DmaSet:
;BC=.dma address to set (i.e., buffa or dmaad)
	jmp	setdmaf
.page
.sbttl	'dirtouser,endofdir,setenddir'
;
;copy the directory entry to the user buffer
;after call to serch or searchn by user code
;
DirToUser:
	lhld	buffa	;source is directory buffer
	lded	dmaad ;destination is user dma address
	lxi	b,recsiz	;copy entire record
	ldir
	ret

;
;return zero flag if at end of directory, non zero
;if not at end (end of dir if dcnt = 0ffffh)
;
EndOfDir:
	lxi	h,dcnt
	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 dcnt to the end of the directory
;
SetEndDir:
	lxi	h,enddir
	shld	dcnt
	ret
.page
.sbttl	'readdir'
;
;read next directory entry
;
ReadDir:
	lhld	dirmax	;in preparation for subtract
	lded	dcnt
	inx	d
	sded	dcnt		;dcnt=dcnt+1
;continue while dirmax >= dcnt (dirmax-dcnt no cy)
	ora	a	;clear carry
	dsbc	d	;hl - de
	jrc	SetEndDir
;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
..1readDir1:
	add	a
	djnz	..1readDir1
;A = (low(dcnt) and dskmsk) shl fcbshf
	sta	dptr	;ready for next dir operation
	ora	a
	rnz		;return if not a new record

	call	SeekDir	;seek proper record
;
;read a directory entry into the directory buffer
;
	call	SetDir		;directory dma
	call	RdBuff	;directory record loaded
	jmp	setdata
.page
.sbttl	'getallocbit,setallocbit,rotr'
;
;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
;
GetAllocBit:
	mov	a,c
	ani	111b
	inr	a
	mov	e,a
	mov	d,a
;d and e are both 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 BC
	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
	jrnz	..rotl
	ret

;
;BC is the bit position of ALLOC to set or reset. The
;value of the bit is in register E.
;
SetAllocBit:
	push	d
	call	GetAllocBit  ;shifted val A, count in D
       ani 11111110b ;mask low bit to zero (may be set)
	pop	b
	ora	c	;low bit of C is masked into A

;
;........................
;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
;
RotR:
	rrc
	dcr	d
	jrnz	RotR		;back into position
	mov	m,a		;back to ALLOC
	ret
.page
.sbttl	'setsharedalloc,getsharedalloc'
;
;Write the shared allocation vector to the
;disk at the track and sector specified by
;curSAtrack/sector from the alloc vector
;space in the BIOS.
;Assumes alloc vec fits on one track and sector<256
;
SetSharedAlloc:
	mvi	A,0ffh
	jmpr Sharall

;
;Read the shared allocation vector in from the
;disk at the track and sector specified by
;curSAtrack/sector into the alloc vector
;space in the BIOS.
;Assumes alloc vec fits on one track and sector<256
;
GetSharedAlloc:
; Force read from disk, not from net read buffer.
	call	forceread
	xra	a
Sharall:
	sta	wrflg	;Read Alloc Vector
			;shared part of loop
	lhld	curSAtrack
	lded	offset	; offset past system tracks
	dad	D	; HL = shared alloc track
	mov	C,L
	mov	B,H	; BC = shared alloc track
	call	settrkf		; BIOS call

	lhld	alloca	; Allocation vector address.
	shld tempAllocAddr ;Used in loop for dma addr.

	lda curSAsector	; First sector of shared alloc.
	sta tempSAsector ; Used to keep current sector
				;within ..Loop.
	lda allocSize ;Size of alloc vector in 128 byte 
			;records.
	mov	B,A	; Use Beg B as ..Loop counter.

..Loop:
	push	B		; Save ..Loop counter.
	lded	tranv	; Address of translate table.
	lxi	H,tempSAsector
	mov	C,M	; Get sector to translate.
	inr	M	; Update to next sector
			;for next time through loop.
	mvi	B,0		; Zero upper byte.
	call	sectran	; BIOS call. Returns 
			;HL= translated sector.
	mov	C,L
	mov	B,H	; Set up for SetSecF call.
	call setsecf ;BIOS call to set sector to read.

	lbcd tempAllocAddr ;Current address of sector 
	call	setdmaf		; Set DMA address 

	lda	wrflg	;Read or Write alloc vector
	ora	A
	jrnz	..write

	call	RdBuff		; Read in sector.
	jmpr	..cont

..write:
	mvi	C,1	;Flag to force write to disk
	call	WrBuff	;Write the sector to the disk

..cont:	lhld	tempAllocAddr
	lxi	D,128
	dad	D	; To next sector address.
	shld	tempAllocAddr

	pop	B
	djnz	..Loop	;B = number of sectors to read.

	jmp SetData ;reset dma address to users dma
.page
.sbttl	'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)
;
ScanDM:
	call	GetDptrAddr	;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
;loop once for each disk map entry
..0scandm:
	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
	jrz	..1scandm
;single byte scan operation
	push	b		;save counter
	push	h		;save map address
	mov	c,m
	mvi	b,0		;BC=block#
	jmpr	..2scandm
;double byte scan operation
..1scandm:
	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
;arrive here with BC=block#, E=0/1
..2scandm:
	mov	a,c
	ora	b		;skip if = 0000
	jrz	..3scandm
	lhld	maxall	;check invalid index
	dsbc	b		;maxall - block#
	cnc	SetAllocBit
;bit set to 0/1
..3scandm:	
	pop	h
	inx	h		;to next bit position
	pop	b		;recall counter
	jmpr	..0scandm	;for another item
.page
.sbttl	'locdircopy'
;
;copy directory location to lret following
;delete, rename, ... ops
;
LocDirCopy:
	lda	dirloc
	jmp	StAret
.page
.sbttl	'serch,searchnext'
;
;search for directory element of length C at info
;
Serch:
	mvi	a,0ffh
	sta	dirloc	;changed if actually found
	sta	stillsearching	;flag to keep on 
				;searching
	lxi	h,lenSearch
	mov	m,c		;lenSearch = C
	lhld	info
	shld	adrSearch	;adrSearch = info
	call	Home	;to start at the beginning
			;and force buffer flush
;
;	now hash name to search for by exclusive
;	oring and rotating characters to produce
;	a single byte hash value
;
	lda	lensearch
	ora	a
	jrz	..beginning	;zero length search
			;is to find everyting
	lxi	b,nameonlylen<8	;b reg is length
; to search, name and type,	c reg is zero starting
; value
	lhld	adrsearch
	inx	h	;skip drive field in hash
..hashloop:
	mov	a,m
	ani	7fh	;strip high bit for hash
	xra	c
	rlc
	mov	c,a
	inx	h
	djnz	..hashloop
	mov	a,c	;get hash result in a
	ora	a
	jrnz	..notbeginning
;
;	are at beggining of directory so set
;	up end of search value appropriately
;
..beginning:
	call	setenddir
	shld	endsearch
	jmpr	searchnext
..notbeginning:
;
;	hashed value in middle of directory.
;	turn 8 bit value into 10 bit value to cover
;	entire possible directory entris, then mask
;	with dirmax to get value into valid range
;
	mvi	h,0
	slar	a
	ralr	h
	slar	a
	ralr	h
	ori	3	;set up so readdir will not
			;think directory entry is in
			;buffer
	lded	dirmax
	ana	e
	mov	l,a
	mov	a,h
	ana	d
	mov	h,a
	shld	dcnt	;place to start search
	shld	endsearch ;place to end search	
	dsbc	d	;if place to start search is
	jrz	..beginning ;end start at beginning
    ;(drop through to SearchNext)
;
;.........................
;search for the next directory element, assuming
;a previous call on search which sets adrSearch and
;lenSearch
;
SearchNext:
	lda	stillsearching	;see if more to search
	ora	a
	jrz	..fin
	call	ReadDir		;read next dir element
;
;	see if all directories have been read
;
	lhld	dcnt
	lded	endsearch
	ora	a
	dsbc	d
	jrnz	..seeifend
	xra	a
	sta	stillsearching	;search ends next time
;
;	see if at end of directory, if so go back
;	to beginning
;
..seeifend:
	call	endofdir
	jrz	searchnext

;not end of directory, scan for match
	lded	adrSearch ;DE=beginning of user fcb
	call	GetDptrAddr	;HL = buffa+dptr
	lda	lenSearch
	mov	c,a		;length of search to c
	mvi	b,0	;b counts up, c counts down
..loop:
	mov	a,c
	ora	a
	jrz	..end

	ldax	d
	cpi	questionmark
	jrz	..ok	;questionmark matches all

	    ;scan next character if not ubytes
	mov	a,b
	cpi	ubytes
	jrz	..ok

	    ;not the ubytes field, extent field
	cpi	extnum		;may be extent field
	ldax	d		;fcb character
	jrz	..ext		;skip to search extent

	sub	m;compare user char with dirbuff entry
	ani	7fh	;mask-out flags/extent modulus
	jrnz	SearchNext	;skip if not matched

	jmpr	..ok		;matched character
..ext:
;A has fcb character
;attempt an extent # match
	push	b		;save counters
	mov	c,m	;directory character to c
;
;compare user/dir char
;compare extent# in A with that in C, return nonzero
;if they do not match
;
	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		;recall counters
	jrnz	SearchNext	;skip if no match

..ok:
;current character matches
	inx	d
	inx	h
	inr	b
	dcr	c
	jmpr	..loop

..end:
;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

..fin:
;end of directory, or empty name
	call	SetEndDir	;may be artifical end
	mvi	a,255
	jmp	StAret
.page
.sbttl	'func15-open,opencopy'
;
;open file
;
Func15:
	call	ClrModNum   ;clear the module number
	call	ReSelect
;	fall thru to Open
;.............................
;
;search for the directory entry, copy to fcb
;
Open:
	mvi	c,namlen
	call	Serch
	inr	a
	rz		;return with lret=255 if end
	   ;not end of directory, copy fcb information
;
;......................
;(referenced below to copy fcb info in
;OpenReel at OpenReel1)
;
OpenCopy:
	call	GetExtAddr
	mov	a,m
	push	psw
	push	h		;save extent#
	call	GetDptrAddr	;HL = .buff(dptr)
	lded	info		;DE=.fcb(0)
	lxi	b,nxtrec ;length of move operation
	push	h		;save .buff(dptr)
	ldir		;from .buff(dptr) to .fcb(0)
;note that entire fcb is copied, including indicators
	call	SetFWflag	;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
	jrz ..rcntopen ;if same, user gets dir reccnt
	mvi	a,0
	jrc	..rcntopen	;user is larger
	mvi	a,128		;directory is larger
..rcntopen: 		;A has record count to fill
	lhld	info
	lxi	d,reccnt
	dad	d
	mov	m,a
	ret
.page
.sbttl	'mergezero'
;
;HL = .fcb1(i), DE = .fcb2(i),
;if fcb1(i) = 0 then fcb1(i) := fcb2(i)
;
MergeZero:
	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
.page
.sbttl	'func16-close'
;
;close file
;
Func16:
	call 	Reselect
;	fall thru to Close
;.........................
;
;locate the directory element and re-write it
;
Close:
	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

	lda	nolock
	inr	a
	cnz	netlock
	mvi	c,namlen
	call	Serch		;locate file
	inr	a
	jrz	..errmerge	;return if not found
				;after unlocking
;merge the disk map at info with that at buff(dptr)
	lxi	b,dskmap
	call	GetDptrAddr
	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
..0merge:
	lda	single
	ora	a
	jrz	..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
	jrnz	..fcbnzero

;fcb(i) = 0
	mov	m,a		;fcb(i) = buff(i)
..fcbnzero:
	ora	a
	jrnz	..buffnzero

;buff(i) = 0
	mov	a,m
	stax	d		;buff(i)=fcb(i)
..buffnzero:
	cmp	m
	jrnz	..errmerge	;fcb(i) = buff(i)
	jmpr	..dmset		;if merge ok

;this is a double byte merge operation
..merged:
	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
	jrnz	..errmerge		;low same

	inx	d
	inx	h		;to high byte
	ldax	d	
	cmp	m
	jrnz	..errmerge		;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
	jrnz	..0merge		;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
	jrc	..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	fcbcopied	;mark as copied
	call SeekCopy  ;ok to "wrdir" here - 1.4 compat
..unlock:jmp	netunlock

;elements did not merge correctly
..errmerge:
	lxi	h,lret
	mvi	m,255	;=255 non zero flag set
	jmpr	..unlock ; return to Close caller.
.page
.sbttl	'func22-make'
;
;make a file
;
Func22:
	call	ClrModNum
	call	Reselect
;	fall thru to Make
;..........................
;create a new file by creating a directory entry
;then opening the file.  If its a floppy initialize
;the allocation vector
;
Make:	call	CheckWrite	;may be write protected
	call	netlock
	lda	mediatype
	ani	notfloppy
	cz	initialize	;init the floppy
	lhld	info
	push	h	;save fcb address, look for e5
;
;	use file name for hash to find place to start
;	looking for e5(unused)
;
	inx	h	;point to name,type
	lxi	d,efcb+1
	lxi	b,nameonlylen
	ldir		;copy name to search string
	lxi	h,efcb
	shld	info		;info = .empty
	mvi	c,1
	call	Serch	;length 1 match on empty entry
	pop	h		;recall info address
	shld	info		;in case we return here
	inr	a
       jrz 	..unlock	;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
	jrnz	..make0

	lxi	h,ubytes
	dad	d		;HL = .fcb(ubytes)
	mov	m,a		;fcb(ubytes) = 0
;now copy entry to the directory
;copy the entire file control block
	mvi	c,0
	mvi	e,fcblen  ;start at 0, to fcblen-1
	call	Copydir
;and set the file write flag to "1"
	call	SetFWflag
..unlock:
	jmp	netunlock
.page
.sbttl	'openreel'
;
;close the current extent, and open the next one
;if possible.  RMF is true if in read mode
;
OpenReel:
	xra	a
	sta	fcbcopied  ;set true if actually copied
	call	Close		;close current extent
;lret remains at enddir if we cannot open the next ext
	lda	lret
	inr	a
	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
	jrz	..modOpen  ;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,fcbcopied	;true if fcb was
				;copied to directory
	ana m ;produces a 00 if not written
	jrz	..0	;go to next physical extent

;result is non zero, so we must be in same logical ext
	jmpr	..1	;to copy fcb information

;extent number overflow, go to next module
..modOpen:
	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
	jrz	..err	;cannot overflow to zero

;otherwise, ok to continue with new module
..0:
	mvi	c,namlen
	call	Serch		;next extent found
	inr	a
	jrnz	..1

;end of file encountered
	lda	rmf
	inr	a	;0ffh becomes 00 if read
	jrz	..err		;sets lret = 1
;try to extend the current file
	call	Make
;cannot be end of directory
	lda	lret	;check status
	inr	a	;255 => 0
	jrz	..err		;with lret = 1
	jmpr	..2

..1:
;not end of file, open
	call	OpenCopy
..2:
	call	GetFcb		;set parameters
	xra	a
	jmp	StAret		;lret = 0

;cannot move to next extent of this file
..err:
	call	SetLret1  ;lret = 1
	jmp	SetFWflag	;ensure that it will
				;not be closed
.page
.sbttl	'seqread,diskread'
;
;sequential disk read operation
;
SeqRead:
	call	reselect
	mvi	a,1
	sta	seqio	;drop through to DiskRead

;
;.....................
;
DiskRead:	;(may enter from seqread)
	mvi	a,true
	sta	rmf  ;read mode flag = true (OpenReel)
;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
	jrc	..recordok

;not enough records in the extent
;record count must be 128 to continue
	cpi	128		;vrecord = 128
	jrnz	..diskeof	;skip if vrecord<>128
	call	OpenReel  ;go to next extent if so
	xra	a
	sta	vrecord		;vrecord=00
;now check for open ok
	lda	lret
	ora	a
	jrnz	..diskeof		;stop at eof

;arrive with fcb addressing a record to read
..recordok:
;error 2 if reading unwritten data
;(returns 1 to be compatible with 1.4)
	call	IsItAllocated		;arecord=0000
	jrz	..diskeof
;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	

..diskeof:
	jmp	SetLret1	;lret = 1
.page
.sbttl	'func21-diskwrite'
;
;write a file
;
Func21:
	call	Reselect
	mvi	a,1
	sta	seqio	;set up for DiskWrite
;	fall thru to diskwrite
;..........................
;
; disk write
;
DiskWrite:
	xra	a	;mvi	a,false
	sta	rmf		;read mode flag
;write record to currently selected file
	call	CheckWrite  ;in case write protected
	lhld	info		;HL = .fcb(0)
	call	CheckRoFile  ;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

;can write the next record, so continue
..0:
	call	IsItAllocated
	mvi	c,0	;marked as normal write 
			;operation for wrbuff
	jnz	..1
;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
;If shared, read in shared alloc vec
	call	netlock
	call	chkcont
	jrz	..01
	call	GetSharedAlloc
	call	open
	call	isitallocated	;see if it was in dir
	jrz	..01
	call	netunlock	;not going to update
	mvi	c,0	;mark as normal write
	jmp	..1		;directory
..01:
	call	DMposition
	sta	dminx		;save for later
	lxi	b,0000h		;may use block zero
	ora	a
	jrz	..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#

;BC = 0000, or previous block #
..nopblock:
;block # to HL
;
;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
	jrz	..righttst	;skip if left=0000

;left not at position zero, bit zero
	dcx	b
	push	d
	push	b		;left,right pushed
	call	GetAllocBit
	rar
	jrnc	..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
	jrnc	..0retblock	;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
	jrnc	..retblock ;return block number if zero

	pop	d
	pop	b  ;restore left and right pointers
	jmpr	..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
	jmpr	..gbdone

..0retblock:
	    ;cannot find an available bit, return 0000
	mov	a,c				;
	ora	b
	jrnz	..lefttst	;also at beginning    
	lxi	h,0000h		;flag for not found
..gbdone:
;arrive here with block# or zero
	mov	a,l
	ora	h
	jrnz	..blockok

;cannot find a block to allocate
	call	netunlock
	mvi	a,2
	jmp	StAret 		;lret=2	

;allocated block number is in HL
..blockok:
	push	H		; Save block #
	call	chkcont
	cnz	SetSharedAlloc
	pop	H		; Get block #
	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
	jrz	..allocwd  ;skip if allocating word
;allocating a byte value
	call	AddH
	mov	m,e		;single byte alloc
	jmpr	..wru		;to continue

;allocate a word value
..allocwd:
	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

;disk write to previously unallocated block
..wru:
	call	chkcont
	jrz	..markallocated
	call GetModNum  ;HL=.fcb(modnum), A=fcb(modnum)
;reset the file write flag to mark as written fcb
	ani	(#fwfmsk) & ^h0ff	;bit reset
	mov	m,a  ;fcb(modnum) = fcb(modnum) and 7fh
	call setfcb  ;update users fcb before closing
	mvi	a,true
	sta	nolock	;dont do lock in close
	call	close	;write out updated
				;directory
	xra	a	;make lret zero, close can
	sta	lret	;return 0,1,2,3 as ok values
			;diskwrite can only return 0
	sta	nolock	;lock next time in close
	call	index	;point back to users record
..markallocated:
	mvi	c,2	;marked as unallocated write
;continue the write operation of no allocation error
;C = 0 if normal write, 2 if to prev unalloc block
..1:
	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
	jrnz	..11

	pop	b
	push	b
	mov	a,c
	dcr	a
	dcr	a
	jrnz	..11		;old allocation  

	push	h	;arecord in hl ret from atran
	lhld	buffa
	mov	d,a		;zero buffa & fill 
..0fill:
	mov	m,a
	inx	h
	inr	d
	jp	..0fill

	call	SetDir
	lhld	a1record
	mvi	c,2

..1fill:
	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
	jrnz	..1fill	;cont until cluster is zeroed

	pop	h
	shld	arecord
	call	setdata
..11:					;
	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
	jrc	..2

	    ;rcount <= vrecord
	mov	m,a
	inr	m		;rcount = vrecord+1
	mvi	c,2  ;mark as record count incremented
..2:
;A has vrecord, C=2 if new block or new record#
	dcr	c
	dcr	c
	jrnz	..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	(#fwfmsk) & ^h0ff	;bit reset
	mov	m,a  ;fcb(modnum) = fcb(modnum) and 7fh
	pop	psw		;restore vrecord

;check for end of extent, if found attempt to open
;next extent in preparation for next write
..noupdate:
	cpi	lstrec		;vrecord=lstrec
	jrnz	..3		;skip if not
;may be random access write, if so we are done
;change next     
	lda	seqio
	cpi	1
	jrnz	..3	;skip next extent open op

;update current fcb before going to next extent
	call	SetFcb
	call	OpenReel	;rmf=false
;vrecord remains at lstrec causing eof if
;no more directory space is available
	lxi	h,lret
	mov	a,m
	ora	a
	jrnz	..nospace

;space available, set vrecord=255
	dcr	a
	sta	vrecord		;goes to 00 next time
..nospace:
	mvi	m,0	;lret = 00 for returned value

..3:
	jmp	SetFcb		;replace parameters
.page
.sbttl	'randseek,rand1seek'
;
;random access seek operation, C=0ffh if read mode
;fcb is assumed to address an active file control block
;(modnum has been set to 11000000b if previous bad 
;seek)
;
RandSeek:
	xra	a
	sta seqio  ;marked as random access operation

Rand1Seek:
	push	b		;save r/w flag
	lded	info	;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
	jrnz	..errseek

;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
	lxi	h,extnum
	dad	d
	mov	a,c		;A=seek ext#
	sub	m
	jrnz	..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
	jrz	..okseek		;same

..ranclose:
	pop	H		; Get R/W mode flag
	push	H		; Save R/W mode flag
	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
	jrz	..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
	jrnz	..okseek	;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
	jrz ..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
	jrz	..badseek		;no dir space

;file make operation successful
..okseek:
	pop	b		;discard r/w flag
	xra	a
	jmp	StAret 		;with zero set	

;fcb no longer contains a valid fcb, mark
;with 1100000b in modnum field so that it
;appears as overflow with file write flag set
..badseek:
	push	h		;save error flag
	call	GetModNum		;HL = .modnum
	mvi	m,11000000b
	pop	h		;and drop through

..errseek:
	pop	b		;discard r/w flag
	mov	a,l
	sta	lret		;lret=#, nonzero
;setfwf returns non-zero accumulator for err
	jmp SetFWflag ;flag set, so subsequent close ok
.page
.sbttl	'rrcompute'
;
;compute random record position for 
;getfilesize/setrandom
;
RRcompute:
	xchg
	dad	d
;DE=.buf(dptr) or .fcb(0), HL = .f(nxtrec/reccnt)
	mov	c,m
	mvi	b,0	;BC = 0000 0000 Xrrr 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 000X errrr rrrr
	mov	a,m
	rrc
	ani	0fh
	add	b
	mov	b,a
;BC = 000X eeee errrr rrrr
	lxi	h,modnum
	dad	d
	mov	a,m		;A=xxxX mmmm
	add	a
	add	a
	add	a
	add	a		;cy=X A=mmmm 0000
	push	psw
	add	b
	mov	b,a
;cy=X, 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 000X possible carry-out
	ret
.page
.sbttl	'setrandom'
;
;set random record from the current file control block
;
SetRandom:
	lhld	info
	lxi	d,nxtrec  ;ready params for computesize
	call	RRcompute	;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

.page
.sbttl	'curselect,select,initialize,chkcont'
CurSelect:
	lda	linfo
	lxi	h,curdsk
	cmp	m
	rz 			;skip if linfo=curdsk

	mov	m,a		;curdsk=info
;	fall thru to Select
;......................
;
;select disk info for subsequent input or output ops
;select the disk drive given by curdsk, and fill
;the base addresses curtrka - alloca, then fill
;the values of the disk parameter block
;
Select:
	lhld	dlog
	lda	curdsk
	mov	c,a		;current disk# to c
	call	hlrotr
	xchg
;lsb of e = 0 if not yet logged - in
	mov	c,a	;restore current disk
	call	seldskf		;HL filled by call
;HL = 0000 if error, otherwise disk headers
	mov 	a,h
	ora	l
	jrnz	..dph
;report select disk error
	lhld	SelErr
	pchl		;to subroutine
..dph:
	mov 	e,m
	inx	h
	mov	d,m
	inx	h		;DE=.tran
	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
	sded	tranv		;.tran vector
	lxi	d,buffa	;HL= source for move, DE=dest
	lxi	b,addlist
	ldir		;addlist filled
; Now fill the disk parameter block
; This is now the DMS extended DPB
	lhld	dpbaddr
	lxi	D,-DMSDPBoffset	; = 16 decimal
	dad	D	; HL = address of control byte
	lxi D,control ;local copy of control address
	lxi	B,dpblist
	ldir
;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
	jrz	..singleset
;high order of maxall not zero, use double dm
	mvi	m,false
..singleset:
	lhld	dlog
	call	HLRcd
;is the disk logged in
	mov	a,l
	rar
	rc 			;return if bit is set

;disk not logged in, set bit and initialize
	lbcd	dlog		;call ready
	call	SetCrDisk
	shld	dlog		;dlog=SetCrDisk(dlog)
;if shared just return,will GetSharedAlloc when needed
	call	chkcont
	jrz	initialize
;
;	insure that shralloc was run on partition
;	if it is shared.  the partition name should
;	be the file name, the extension should be !
;	del,del(7f). user number 15. if it does not
;	exist consider it a fatal error
;
	lxi	d,lockname  ;place to stuff file name
	mvi	a,15	;user number
	stax	d
	inx	d
	lxi	h,diskname	;partition name
	lxi	b,prtnmlen
	ldir
	mvi	a,'!'
	stax	d
	inx	d
	mvi	a,7fh	;delete char
	stax	d
	inx	d
	stax	d
	lhld	info	;save
	push	h
	lxi	h,lockname
	shld	info	;point to shralloc fcb
	mvi	c,12
	;search user number thru
	call	serch	;extension
	pop	h
	shld	info	;restore
	lxi	h,lockname
	mvi m,prtnmlen+lenprtnminsert ;restore for lock
	inr	a
	rnz		;done
	lhld	sharerr
	pchl		;head off to error routine

;
;initialize the current disk,i.e build allocation
;vector
;lret = false ;set to true if $ file exists
;
initialize:
	call	Home    ;home disk
;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
..0init:
	mvi m,0
	inx	h		;alloc(i)=0
	dcx	b 		;count length down
	mov	a,b
	ora	c
	jrnz	..0init
;set the reserved space for the directory
	lded	dirblk	
	lhld	alloca		;HL=.alloc()
	mov	m,e
	inx	h
	mov	m,d	;sets reserved directory blks
;allocation vector initialized
	call	SetEndDir		;dcnt = enddir
;read directory entries and check for allocated storage
..2init:
	call	ReadDir
	call	EndOfDir
	rz		;return if end of directory
;not end of directory, valid entry
	call	GetDptrAddr	;HL = buffa + dptr
	mvi	a,empty
	cmp	m
	jrz	..2init		;go get another item
;not empty, user code the same
	lda	usrcode
	cmp	m
	jrnz	..pdollar
;same user code, check for '$' submit
	inx	h
	mov	a,m		;first character
	sui	'$'		;dollar file
	jrnz	..pdollar
;dollar file found, mark in lret
	dcr	a
	sta	lret		;lret = 255

;check if at end of logical directory
;optional for non shared drive
..pdollar:
;now scan the disk map for allocated blocks
	mvi	c,1		;set to allocated
	call	ScanDM
	jmpr	..2init		;for another entry

;
; check if partition marked shared
;	on return:
;	zero flag set - not shared
;	nonzero		- shared
chkcont:		
	lda	control		;bit 6 = 1 means shared
	bit	FLGshared,A
	ret
.page
.sbttl	'reselect'
;
;check current fcb to see if reselection necessary
;
ReSelect:
	mvi	a,true
	sta	resel		;mark possible reselect
	lhld	info
	mov	a,m		;drive select code
	ani	11111b	;non zero is auto drive select
	dcr a  ;drive code normalized to 0..30, or 255
	sta	linfo		;save drive code
	cpi	30
	jrnc	..noselect

    ;auto select function, save curdsk
	lda	curdsk
	sta	olddsk		;olddsk=curdsk
	mov	a,m
	sta	fcbdsk		;save drive code
	ani	11100000b
	mov	m,a		;preserve hi bits
	call	CurSelect

..noselect:
	    ;set user code
	lda	usrcode		;0...31
	lhld	info
	ora	m
	mov	m,a
	ret
.page
.sbttl	'initialized data'
;
;	data areas
;
;	INITIALIZED DATA
;
nolock:	.byte	false	;true if no locking to be done
			;in close routine, false
			;if locking to be done by close
efcb:	.byte	empty	;0e5=available dir entry
	.blkb	nameonlylen ;for file name in make 
			;function
rodsk:	.word	0	;read only disk vector
dlog:	.word	0	;logged-in disks
dmaad:	.word	tbuff	;initial dma address
    ; lockName is filled with the partition name
    ;(at DBP-11) to be locked for sharing purposes.
    ; for MPM rec0 and rec1 are rec # in file to be
    ; locked. Used by func 42 and 43	
lockName:.byte	prtnmlen + lenprtnminsert ;for length 
			;of string
	.blkb	prtnmlen + lenprtnminsert ;max length
	.ife mpmpresent,[
rec0:	.byte	0
rec1:	.byte	0	]
	
lockcount:.blkb	2	;count of attempts to lock
			;a string
;	common values shared between bdosi and bdos
;
usrcode:.byte	0	;current user number
curdsk:	.byte	0	;current disk number
info:	.blkb	2	;information address set to DE
aret:	.blkb	2	;address value to return
lret	==	aret	;low(aret)
;
;	data for bdos interface module
;
compcol:.byte	0	;true if computing col pos
strtcol:.byte	0	;starting col pos after read
column:	.byte	0	;column position
listcp:	.byte	0	;listing toggle
kbchar:	.byte	0	;initial key char = 00
entsp:	.blkb	2	;entry stack pointer
;
;
;	24 level stack
;
	.ascii	'Copyright (c) 1983 Digital '
	.ascii	'Microsystems '
	.byte	76h,76h,76h,76h,76h,76h,76h,76h
lstack:
;
;	dispatch table for functions
;
functab:
	.word	wbootf, func1, tabout, func3
	.word	punchf, listf, func6, func7
	.word	func8, func9, read, func11
diskf	==	(.-functab)/2	;disk funcs
	.word	func12,func13,curselect,func15
	.word	func16,func17,func18,func19
	.word	seqread,func21,func22,func23
	.word	func24,func25,func26,func27
	.word	setro,func29,func30,func31
	.word	func32,func33,func34,func35
	.word	setrandom,func37,func38,func39
	.word	func40
	.ife	mpmpresend,[
	.word	func41,func42,func43]
nfuncs	==	(.-functab)/2
.page
.sbttl	'non initialized data'
;
;	NON INITIALIZED DATA
;
;	curtrka - alloca are set upon disk select
;    (data must be adjacent, do not insert variables)
;
tranv:	.blkb	word ;current translate vector address
cdrmaxa:.blkb	word	;pointer to cur dir max value
curtrka:.blkb	word	;current track address
curreca:.blkb	word	;current record address
buffa:	.blkb	word ;pointer to directory dma address
dpbaddr:.blkb 	word ;current disk parameter block addr
checka:	.blkb	word ;current checksum vector address
alloca:	.blkb	word ;current allocation vector address
addlist	==	.-buffa	;address list size

;
;	control - offset obtained from disk parm block
;	at dpbaddr (data must be adjacent, do not insert
;	variables)
;
control:	.blkb	1	; bit 6 is the shared
			;alloc indicator. Set = 1.
mxChkVec:	.blkb	2 ; Maximum check vector size
mxAlcVec:	.blkb	2 ; Maximum alloc vector size
diskName:	.blkb	prtnmlen	; Name of partition
hdVolume:	.blkb	1 ; Hard disk volume number
mediaType:	.blkb	1	; Tells kind of disk.
unitNum:	.blkb	1	; Partition number on 
				;hard disk.

sectpt:	.blkb	word	;sectors per track
blkshf:	.blkb	byte	;block shift factor
blkmsk:	.blkb	byte	;block mask
extmsk:	.blkb	byte	;extent mask
maxall:	.blkb	word	;maximum allocation number
dirmax:	.blkb	word	;largest directory number
dirblk:	.blkb	word	;reserved allocation bits for
			;directory
chksiz:	.blkb	word	;size of checksum vector
offset:	.blkb	word	;offset tracks at beginning

curSAsector:	.blkb	1	; address of current
				;shared alloc sector
curSAtrack:	.blkw	1	; address of current
				;shared alloc track
allocSize:	.blkb	1	; Address of the size
				;of the alloc vector in
				;128 byte records
dpblist	==	.-control	;size of area

;
;	local variables
;
fcbcopied:
	.blkb	byte	;set true if copyfcb called
rmf:	.blkb	byte	;read mode flag for openreel
dirloc:	.blkb	byte	;directory flag in rename, etc.
seqio:	.blkb	byte	;1 if sequential i/o
linfo:	.blkb	byte	;low(info)
dminx:	.blkb	byte	;local for diskwrite
lenSearch:.blkb	byte	;search length
adrSearch:.blkb	word	;search address
tinfo:	.blkb	word	;temp for info in "make"
single:	.blkb	byte	;set true if single byte
			;allocation map
resel:	.blkb	byte	;reselection flag
fcbdsk:	.blkb	byte	;disk named in fcb
olddsk:	.blkb	byte	;disk on entry to bdos
rcount:	.blkb	byte	;record count in current fcb
extval:	.blkb	byte	;extent number and extmsk
vrecord:.blkb	byte	;current virtual record
arecord:.blkb	word	;current actual record
a1record: .blkb	word	;current actual block# * blkmsk
wrflg:	.byte	0 ;0=read, ff=write SHR ALL Vector
;
;    The following two variables are used in
; Get/SetSharedAlloc and keep track in the
; sector read/write loop of the sector currently being
; used, and the current dma address to read/write from.
;
tempSAsector:	.byte	0	; local sector count.
tempAllocAddr:	.word	0	; local dma address.
;
;	local variables for directory access
;
dptr:	.blkb byte ;directory pointer 0,1,2,3
dcnt:	.blkb word ;directory counter 0,1,...,dirmax
drec:	.blkb word ;directory record 0,1,...,dirmax/4
endsearch:.blkb word ;directory entry to end search on
stillsearching:.blkb byte ;flag for searchnext
		;true - more to search
		;false - nothing left to search

	.ifg	.-(location + lenbdos),[
	.prntx /bdos overflow/][
	.prntx /bdos len ok/]
;
; Bios address is now set at beginning by a '.loc'
;

zBiosCheck == (.+0FFh) & 0FF00h ;next 256 byte boundary

zBios	==	bios
zend	==	.

	.end
