	title	'Resident Portion of Banked BDOS'
;***************************************************************
;***************************************************************
;**                                                           **
;**   B a s i c    D i s k   O p e r a t i n g   S y s t e m  **
;**                                                           **
;**  R e s i d e n t  P o r t i o n  -  B a n k e d  B D O S  **
;**                                                           **
;***************************************************************
;***************************************************************

;/*
;  Copyright (C) 1978,1979,1980
;  Digital Research
;  P.O. Box 579
;  Pacific Grove, CA 93950
;
;  Revised:
;    11 Jan 80 by Thomas Rolander
;*/

on	equ	0ffffh
off	equ	00000h
;
	org	0000h
base	equ	$
;
;	XDOS jump table below BDOS origin
pdisp	equ	$-3
xdos	equ	pdisp-3

;	equates for non graphic characters
ctlc	equ	03h	;control c, abort
ctld	equ	04h	;control d, detach
ctle	equ	05h	;physical eol
ctlh	equ	08h	;backspace
ctlp	equ	10h	;prnt toggle
ctlq	equ	11h	;prnt owner 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
;
;	BDOS call equates
dskinit		equ	13
dskslct		equ	14
dsksetDMA	equ	26
setusercode	equ	32
;
;	XDOS call equates
poll		equ	131
makeque		equ	134
readque		equ	137
condreadque	equ	138
writeque	equ	139
condwriteque	equ	140
dispatch	equ	142
terminate	equ	143
attach		equ	146
detach		equ	147
sysdtadr	equ	154
;
;	Process Descriptor Offsets
pname		equ	6
console		equ	14
memseg		equ	15
thread		equ	18
disksetDMA	equ	20
diskselect	equ	22
diskparams	equ	23
searcha		equ	26
drvact		equ	28
;
;	System Data Page Offsets
userstackflag	equ	3
brkvctr		equ	48
usrstkregion	equ	80
;
;	MP/M Data Page Offsets
rlros		equ	5
thrdrt		equ	17
cnsatt		equ	20
msegtbl		equ	150
;
;*****
;
;	enter here from the user's program with function number
;	in c, and information address in d,e
	jmp	xbdos	;to xbdos handler
	jmp	bios	;to bios jump table base address
;
;	bdos/xdos initialization code
syinit:
	;HL = sysdat page address
	shld sysdat
	mvi l,7! lxi b,bnkbdos
	mov a,m! mov e,a! stax b! inx b! inx h
	mov a,m! mov d,a! stax b
	xchg! inx h! inx h! inx h
	shld bnkbdosinit
bnkbdosinit equ $+1
	call $-$	 ;initialize the banked bdos
	jmp syinitcontd

extjmptbl:
	jmp	extreboot
	jmp	rlr
	jmp	getrlradr
	jmp	dsplynm
	jmp	xprint
	jmp	xcrlf
	jmp	conoutx
	jmp	getmemseg
	jmp	coninf
	jmp	homef
	jmp	seldskf
	jmp	settrkf
	jmp	setsecf
	jmp	setdmaf
	jmp	extreadf
	jmp	extwritef
	jmp	sectran

syinitcontd:
	lhld sysdat! mov c,h
	mvi l,252! mov a,m! inx h! mov h,m
	mov l,a! lxi d,0005! dad d
	shld rlradr! mov h,c
	mvi l,userstackflag! mov a,m! sta usrstkflg
	dcr l! mov l,m! mvi h,0 ;HL = RST #
	mov c,l ;put RST # into C for use by SYSINITF
	dad h! dad h! dad h ;HL = breakpoint address
	mvi m,0C3h! inx h ;store jump to brkpt hndlr
	lxi d,brkpt ;DE = brkpt entry address
	mov m,e! inx h! mov m,d
	;initialize jmp at 0000H to fake BIOS jump table
	mvi a,0C3H! sta 0000H
	lxi h,drctjmptbl! shld 0001H
	;execute the XIOS SYSINIT function
	call syinitf
	ei ;in case it was not done in sysinit
	;create disk mutual exclusion queue
	mvi c,makeque! lxi d,diskcqcb! call xdos
	mvi c,writeque! lxi d,MXDisk! call xdos
	;create printer mutual exclusion queue
	mvi c,makeque! lxi d,listcqcb! call xdos
	mvi c,writeque! lxi d,MXList! call xdos
	;get the directory buffer address
	mvi c,0! call seldskf
	lxi d,8! dad d! mov e,m! inx h! mov d,m
	xchg! shld dirbufa
	;initialize disk system
	mvi c,dskinit! jmp bdos
	;ret ;initialization is complete
;
CoNm:
	db 'COPYRIGHT (C) 1980, '
	db ' DIGITAL RESEARCH '
Serial:
	db '654321'

lstack	equ	Serial+4

entsp	equ	lstack	;BDOS entry stack pointer

dtbl	equ	$
	org	((dtbl-base)+0ffh) and 0ff00h
; *** this table is page aligned
;	BIOS jump table for *.COM file support
	jmp bootf
drctjmptbl:
	jmp wbootf
	jmp bconst
	jmp bconin
	jmp bconout
	jmp blist
;
;  Support for direct BIOS console & list device I/O
;
bconst:	call setflg0
	lxi h,console! dad d! mov d,m
	jmp constf

bconin:	call setflg0! mvi c,3! jmp xbdos

bconout:call setflg0! mov e,c! mvi c,4! jmp xbdos

blist:	call setflg0! mov e,c! mvi c,5! jmp xbdos

setflg0:
	lhld rlradr! mov e,m! inx h! mov d,m
	lxi h,pname! dad d
	mov a,m! ori 80h! mov m,a
	ret

;	Disk and List data structures
diskcqcb:
	;disk mutual exclusion circular queue control block
	dw	$-$	;link
	db	'MXDisk  ' ;name
	dw	0	;message length
	dw	1	;number of messages
	dw	$-$	;dq process head
	dw	$-$	;nq process head
	dw	$-$	;msgin
	dw	$-$	;msgout
	dw	$-$	;msgcnt
	dw	$-$	;owner Process descriptor adr
MXDisk:
	;disk user queue control block
	dw	diskcqcb

listcqcb:
	;list mutual exclusion circular queue control block
	dw	$-$	;link
	db	'MXList  ' ;name
	dw	0	;message length
	dw	1	;number of messages
	dw	$-$	;dq process head
	dw	$-$	;nq process head
	dw	$-$	;msgin
	dw	$-$	;msgout
	dw	$-$	;msgcnt
	dw	$-$	;owner Process Descriptor adr
MXList:
	;list user queue control block
	dw	listcqcb

xbdos:	;arrive here from user programs
	mov a,c! ora c ; test function code
	jz reboot ;zero terminates calling process
	jp notXDOS ;jump if a BDOS call

	call XDOS ;func >= 128 is a XDOS call
	mov a,l ;XDOS returns address put low byte into A
	ret

badfunc:
	;invalid function code
	lxi h,0ffffh! mov a,l! ret

brkpt:	;debugger breakpoint entry
	di! shld svdhl! pop h! shld svdrt! push psw
	;set HL = RLR
	lhld rlradr! mov a,m! inx h! mov h,m! mov l,a
	mvi a,memseg! add l! mov l,a
	mvi a,0! adc h! mov h,a ;HL = .pd.memseg
	mov a,m! add a! adi brkvctr
	lhld sysdat! mov l,a ;HL = brkpt hndlr address
	mov a,m! inx h! mov h,m! mov l,a
	shld jmptobrk+1
	pop psw! lhld svdrt! push h! lhld svdhl
jmptobrk:
	jmp	$-$

restore:
	;restore user stack
	xchg! pop h! sphl! xchg ;get user stack pointer
	ret

notXDOS:
	lda usrstkflg! ora a
	jz BDOS ; if flag set then change stack
	; get memory segment index
	lhld rlradr! mov a,m! inx h
	mov h,m! mov l,a
	mvi a,memseg! add l! mov l,a
	mvi a,0! adc h! mov h,a
	mov a,m ; A = memory segment index
	inr a! jz BDOS ;no stack change if system process call
	dcr a! add a! adi usrstkregion
	lhld sysdat! mov l,a
	mov a,d! mov b,e ;save DE in AB
	mov e,m! inx h! mov d,m
	lxi h,0! dad sp
	xchg! sphl! push d ;set & save user SP
	lxi h,restore! push h ; setup return address to restore stack
	mov d,a! mov e,b ;restore DE

BDOS:
	mov a,c! cpi diskf! jc cnsfunc ;jump if not disk i/o
	cpi nfuncs! jnc badfunc ;skip if invalid #
	push d! push b ;save info & func

	;test for 'live console' suppression, indicated by
	; process name with high order bit of first char "on"
	lhld rlradr! mov a,m! inx h! mov h,m! mov l,a
	lxi b,pname! dad b! mov a,m! ani 80h
	cz func11 ;simulate 'live console' with kbd status chk

	;obtain entry by getting disk mutual exclusion message
	mvi c,readque! lxi d,MXDisk! call XDOS

	;setup & jump to banked bdos
	pop b! pop d ;restore info & func
	lxi h,0! dad sp! shld entsp
	lxi sp,lstack

	;perform the required buffer transfers from
	; the user in common memory
	mov a,c! cpi 17 ;search ?
	jnz skipsrch
	call rlr! push d! lxi d,searcha! dad d! pop d
	mov m,e! inx h! mov m,d
	jmp skipsrchnxt
    skipsrch:
	cpi 18 ;search next ?
	jnz skipsrchnxt
	call rlr! lxi d,searcha! dad d
	mov e,m! inx h! mov d,m
    skipsrchnxt:
	mvi b,0! lxi h,dfctbl-12! dad b
	mov a,m! push psw! push d
	rar! jc cpydmain
	rar! jc cpyfcbin
	jmp nocpyin
    cpydmain:
	call rlr! lxi d,disksetdma! dad d
	mov e,m! inx h! mov d,m
	xchg! shld dmabufa! xchg
	lhld dirbufa! mvi b,128
	call move
	pop d! push d
    cpyfcbin:
	lxi h,commonfcb! mvi b,36
	call move
	lxi d,commonfcb

    nocpyin:
	call getmemseg! sta usermemseg
	mvi m,0 ;set memseg to 0 (memseg #0 must be bank zero)
	push d! push b ;save info & func
	mvi c,dispatch! call xdos
	pop b! pop d

bnkbdos equ $+1
	call $-$

	shld aret
	call getmemseg! lda usermemseg! mov m,a
	mvi c,dispatch! call xdos

	pop d! pop psw ;resore dfctbl byte & fcb address
	ral! jc dmacpyout
	ral! jnc nocpyout
    fcbcpyout:
	lxi h,commonfcb! xchg! mvi b,36
	jmp cpyoutcmn
    dmacpyout:
	lhld dirbufa! xchg! lhld dmabufa! mvi b,128
    cpyoutcmn:
	call move

    nocpyout:
	lhld entsp! sphl ;user stack restored
	lhld aret! push h
	;release disk mutual exclusion message
	mvi c,writeque! lxi d,MXDisk! call XDOS
	;function done
	pop h! mov a,l! mov b,h ;BA = HL = aret
	ret

move:
	;move data length of B from source DE to
	;destination HL
	inr b ;in case of length=0
	move0:
		dcr b! rz
		ldax d! mov m,a
		inx d! inx h
		jmp move0

cnsfunc:
	mov a,c! mov c,e! mov b,d
	lxi h,functab! mov e,a! mvi d,0 ;DE=func, HL=.functab
	dad d! dad d! mov e,m! inx h! mov d,m ;DE=functab(func)
	xchg! pchl ;dispatched
;
;	dispatch table for functions
functab:
	dw	bootf,func1,func2,func3
	dw	func4,listf,func6,func7
	dw	cmnret,func9,func10,func11
diskf	equ	($-functab)/2

nfuncs	equ	40	;must match with banked bdos # fns

;
func1:
	;return console character with echo
	call attcns! call conech
	mov l,a! ret
;
func2:
	;write console character with tab expansion
	call attcns! jmp tabout
;
func3:
	;return raw unattached console character
	call testcnsatt
	jmp dirinp
;
func4:
	;write raw unattached console character
	call testcnsatt
	jmp conoutf
;
;func5:
	;write list character
	;write to list device
	;jmp listf
;
func6:
	;direct console i/o - read if 0ffh
	call attcns
	mov a,c! inr a! jz dirinp ;0ffh => 00h, means input mode
	         inr a! jz stsinp ;0feh => 00h, means status chk
		;direct output function
		jmp conoutf
	dirinp:
		;this differs from CP/M 2.0 which does const
		;and returns zero if not ready
		;character is ready, get it
		lxi h,kbchar! call ofsthl
		mov a,m! mvi m,0! ora a
		cz coninf ;to A
		mov l,a! ret
	stsinp:
		;direct console status input
		call constf ;to A
		mov l,a! ret
;
func7:
	;return io byte
	;*** Not implemented in MP/M 1.0 ***
	xra a
	mov l,a! ret
;
;func8:
	;set i/o byte
	;*** Not implemented in MP/M 1.0 ***
	;ret
;
func9:
	;write line until $ encountered
	;BC = string address
	call attcns! jmp print ;out to console
;
func10:
	;read a buffered console line
	call attcns! jmp read
;
func11:
	;check console status
	call testcnsatt
	jz doconbrk
		mvi c,dispatch! call xdos
		xra a! mov l,a! ret
	doconbrk:
		call conbrk
		mov l,a
;
cmnret:
		ret
;
getrlradr:
	lhld rlradr! ret

rlr:
	;set HL = contents of Ready List Root
	lhld rlradr! mov a,m! inx h! mov h,m! mov l,a
	ret
;
getmemseg:
	;set A = memory segment #
	call rlr ;HL = Ready List Root
	mvi a,memseg! add l! mov l,a
	mvi a,0! adc h! mov h,a ;HL = .pd.memseg
	mov a,m! ret
;
testcnsatt:
	;test to determine if console is attached
	;Zero = attached, D = Console #
	call rlr! xchg ;DE = Ready List Root
	lxi h,console! dad d! mov a,m! push psw! push b
		lhld rlradr! lxi b,cnsatt-rlros! dad b
		add a! mov c,a! mvi b,0! dad b
		mov a,m! cmp e! jnz testext
		inx h! mov a,m! cmp d
	testext:
	pop b! pop d
	mvi e,0 ;cns req'd flag false
	ret
;
attcns:
	;attach console if req'd
	call testcnsatt
	mvi e,0ffh! rz ;cns req'd flag true
	push b! push d!
		mvi c,attach! call xdos
	pop d! pop b!
	ret
;
ofsthl:
	;offset HL by console # (in D)
	push psw
		mov a,d! add l! mov l,a
		mvi a,0! adc h! mov h,a
	pop psw
	ret

;
;	console handlers

constx:
	push d! call constf! pop d! ret

coninx:
	;returns char & cond code = NZ if raw input
	push d! call rlr! lxi d,pname! dad d
	pop d! push d! ;restore console #
	mov a,m! ani 80h! push psw
	call coninf
	mov b,a! pop psw! mov a,b
	pop d! ret

conoutx:
	push d! call conoutf! pop d! ret

conin:
	;read console character to A
	lxi h,kbchar! call ofsthl
	mov a,m! mvi m,0! ora a! rnz
	;no previous keyboard character ready
	call getchr ;get character externally and test it
	jmp conin ;only exit is with kbchar <> 0
	;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 not graphic
;
conbrk:	;check for character ready
	call constx! ani 1
	lxi h,kbchar! call ofsthl
	jnz pgetchr ;jump if char to be read in
	mov a,m! ora a! rz ;return if no char in kbchar either
	jmp conb1 ;active kbchar
	pgetchr:
		mvi m,0 ;clear kbchar to prepare for new char
		;character ready, read it
	getchr: ;entry point used by conin
		call coninx ;to A
		jnz conb0; skip char testing if pd.pname.f0 is "on"
		cpi ctls! jnz notcts ;check stop screen function
		;found ctls, read next character
		call coninx ;to A
		cpi ctlc! jz controlc ;ctlc implies re-boot
		;not a reboot, act as if nothing has happened
		xra a! ret ;with zero in accumulator
	notcts:
		;not a control s, control d?
		cpi ctld! jnz notctd
		;found ctld, detach console
		push d! mvi c,detach! call XDOS
		;then attach console back
		; unless cns not req'd
		pop d! mov a,e! ora a
		rz! push d ;return if cns not req'd
		mvi c,attach! call XDOS! pop d
		;print console attach message
		lxi b,atchmsg! call xprint
		call rlr
	dsplynm:
		lxi b,pname! dad b! mvi e,8
		dsploop:
			mov c,m! push h! push d! call conoutx
			pop d! pop h! inx h! dcr e
			jnz dsploop
		inr e ;cns req'd set true
	xcrlf:
		;output crlf without CONBRK calls
		mvi c,cr! call conoutx
		mvi c,lf! call conoutx
		xra a! ret ;with zero in A

	notctd:
		;not a control d, control c?
		cpi ctlc! jnz conb0
	    controlc: ;entry point
		;test to see if this is a user process
		call getmemseg! inr a
		rz ;ignore ^C if system process running
		;print Abort (Y/N) ?
		lxi b,abtmsg! call query
			jz reboot
		xra a! ret ;with zero in A
	conb0:
		;character in accum, save it
		lxi h,kbchar! call ofsthl! mov m,a
	conb1:
		;return with true set in accumulator
		mvi a,1! ret
;
query:
	call xprint! call coninx! push psw
		mov c,a! call conoutx
		mvi c,cr! call conoutx
		mvi c,lf! call conoutx
	pop psw
	ani 5fh! cpi 'Y'
	ret
;
conout:
	;compute character position/write console char from C
	;compcol = true if computing column position
	lxi h,compcol! call ofsthl
	mov a,m! ora a! jnz compout
		;write the character, then compute the column
		;write console character from C
		push b!	call conoutx ;externally, to console
		call conbrk ;check for screen stop function
		pop b! push b! push d ;recall/save character & con #
		;may be copying to the list device
		lxi h,listcp! call ofsthl
		mov a,m! ani 01h! cnz listf ;to printer, if so
		pop d! pop b ;recall the character & con #
	compout:
		mov a,c ;recall the character
		;and compute column position
		lxi h,column! call ofsthl ;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 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, eol?
			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
		call ldacolumn! ani 111b ;column mod 8 = 0 ?
		jnz tab0 ;back for another if not
	ret
;
backup:
	;back-up one screen position
	call pctlh! mvi c,' '! call conoutx ;jmp pctlh
;
pctlh:
	;send ctlh to console without affecting column count
	mvi c,ctlh! jmp conoutx
	;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:
		call ldacolumn! lxi h,strtcol! call ofsthl
		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
;
xprint:
	;print routine which does not CONBRK
	;BC = string address, string terminated with a '$'
	ldax b! cpi '$'! rz
	push b! mov c,a! call conoutx! pop b
	inx b! jmp xprint
;
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
;
pread:	;entry to read, restores buffer address
	pop b
read:	;BC = address (max length, current length, buffer)
	push b ;save buffer address for possible ^X or ^U
	call ldacolumn
	lxi h,strtcol! call ofsthl
	mov m,a ;save start for ctl-x, ctl-h
	mov h,b! mov l,c! 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
			call ldacolumn
			lxi h,compcol! call ofsthl
			mov m,a ;col > 0
			;compcol > 0 marks repeat as length compute
			jmp linelen ;uses same code as repeat
		noth:
			;not a backspace
			cpi rubout! jnz notrub ;rubout char?
			;rubout encountered, rubout if possible
			mov a,b! ora a! jz readnx ;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
			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
			lxi h,strtcol! call ofsthl
			xra a! mov m,a ;start position = 00
			jmp readn0 ;for another character
		note:
			;not end of line, list toggle?
			cpi ctlp! jnz notp ;skip if not ctlp
			mvi a,01h! jmp ctlpqcmn
		notp:
			cpi ctlq! jnz notq ;skip if not ctlq
			mvi a,80h
		    ctlpqcmn:
			;list toggle - change parity
			push h ;save next to fill - 1
			push b! push d
			lxi h,listcp! call ofsthl ;HL=.listcp flag
			xra m! mov m,a ;listcp=-listcp
			push h ;save address of listcp
			jnz prntron ; jump if printer to be turned on
			prntroff:
				;return list mutex queue message
				mvi m,0! ;zero listcp(console)
				mvi c,condwriteque! lxi d,MXList
				call XDOS
				pop h! jmp ctlpxit
			prntron:
				;test for ^p or ^q already "on"
				cpi 81h! jz prntroff
                                ;cond. read list mutex message
				mvi c,condreadque
				lxi d,MXList! call XDOS
				mov a,l! ora a
				pop h! jz ctlpxit
				;printer busy, could not ^p
				mvi m,0! lxi b,pbsymsg
				;D = console #
				pop d! push d
				call xprint
			ctlpxit:
				pop d! pop b
				pop h! jmp readnx ;for another char
		notq:
			;not a ctlp, line delete?
			cpi ctlx! jnz notx
			pop h ;discard start position
			;loop while column > strtcol
			backx:
				lxi h,strtcol! call ofsthl
				mov a,m! lxi h,column! call ofsthl
				cmp m! jnc pread ;start again
				dcr m ;column = column - 1
				call backup ;one position
				jmp backx
		notx:
			;not a control x, control u?
			cpi ctlu! jnz notu ;skip if not
			;delete line (ctlu)
			call crlfp ;physical eol
			pop h ;discard starting position
			jmp pread ;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 lengths
			;original BC still remains pushed
			push h ;save next to fill
			lxi h,compcol! call ofsthl
			mov a,m! ora a ;>0 if computing length
			jz readn0 ;for another char if so
			;column position computed for ctlh
			lxi h,column! call ofsthl! sub m ;diff > 0
			lxi h,compcol! call ofsthl
			mov m,a ;count down below
			;move back compcol-column spaces
		backsp:
			;move back one more space
			call backup ;one space
			lxi h,compcol! call ofsthl! 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,b ;len to A
			;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
			pop h ;discard buffer address
			mvi c,cr! jmp conout ;return carriage
			;ret
;
ldacolumn:
	lxi h,column! call ofsthl! mov a,m! ret

pbsymsg:
	db	cr,lf,'Printer Busy.',cr,lf,'$'

abtmsg:
	db	cr,lf,'Abort (Y/N) ?','$'

atchmsg:
	db	cr,lf,'Attach:$'

;
;	data areas
;
nmbcns	equ	16

compcol:db	0	;true if computing column position
	rept	nmbcns-1
	db	0
	endm
strtcol:db	0	;starting column position after read
	rept	nmbcns-1
	db	0
	endm
column:	db	0	;column position
	rept	nmbcns-1
	db	0
	endm
listcp:	db	0	;listing toggle
	rept	nmbcns-1
	db	0
	endm
kbchar:	db	0	;initial key char = 00
	rept	nmbcns-1
	db	0
	endm

;*********
;
;	intercept bios boot, readf & writef to switch banks

extreboot:
	call getmemseg! lda usermemseg! mov m,a
	mvi c,dispatch! call xdos
	lxi h,0ffffh! shld aret
	lda usermemseg! inr a
	jz nocpyout ;system process - release MXDisk & return
;
reboot:
	;terminate the calling process
	mvi c,terminate! lxi d,0
	jmp xdos


extreadf:
	call getmemseg! lda usermemseg! mov m,a
	mvi c,dispatch! call xdos
	call readf
	jmp extcommon

extwritef:
	call getmemseg! lda usermemseg! mov m,a
	mvi c,dispatch! call xdos
	call writef
    extcommon:
	push psw
	call getmemseg! mvi m,0
	mvi c,dispatch! call xdos
	pop psw! ret

;
;	Local Data Segment
rlradr:	ds	2	;address of Ready List Root
sysdat:	ds	2	;address of system data page
usrstkflg: ds	1	;user stack flag, 0ffh=users stack
svdhl:	ds	2	;saved HL at breakpoint entry
svdrt:	ds	2	;saved return address at breakpoint entry
;
dirbufa: ds	2	;directory buffer address
dmabufa: ds	2	;dma buffer address
usermemseg: ds	1	;saved user mem seg index
aret:	ds	2	;address value to return

commonfcb:
	ds	36	;fcb copy in common memory

;
;	Disk Function Copy Table
;
dmain	equ	00000001b	;dma copy on entry
fcbin	equ	00000010b	;fcb copy on entry
dmaout	equ	10000000b	;dma copy on exit
fcbout	equ	01000000b	;fcb copy on exit

dfctbl:
	db 0			; 12=return version #
	db 0			; 13=reset disk system
	db 0			; 14=select disk
	db fcbin+fcbout		; 15=open file
	db fcbin		; 16=close file
	db fcbin+dmain+dmaout	; 17=search first
	db fcbin+dmain+dmaout	; 18=search next
	db fcbin		; 19=delete file
	db fcbin+fcbout		; 20=read sequential
	db fcbin+fcbout		; 21=write sequential
	db fcbin+fcbout		; 22=make file
	db fcbin		; 23=rename file
	db 0			; 24=return login vector
	db 0			; 25=return current disk
	db 0			; 26=set DMA address
	db 0			; 27=get alloc address
	db 0			; 28=write protect disk
	db 0			; 29=get R/O vector
	db fcbin		; 30=set file attributes
	db 0			; 31=get disk param addr
	db 0			; 32=get/set user code
	db fcbin+fcbout		; 33=read random
	db fcbin+fcbout		; 34=write random
	db fcbin+fcbout		; 35=compute file size
	db fcbin+fcbout		; 36=set random record
	db 0			; 37=drive reset
	db 0			; 38=access drive
	db 0			; 39=free drive


	ds	6	;reserve space for two jump instructions
;
;	bios external jump table
last:
	org	(((last-base)+255) AND 0ff00h) - 6
	jmp xbdos
	jmp pdisp
;
;	bios access table
bios	equ	$		;base of the bios jump table
bootf	equ	bios		;cold boot function
wbootf	equ	bootf+3		;warm boot function
constf	equ	wbootf+3	;console status function
coninf	equ	constf+3	;console input function
conoutf	equ	coninf+3	;console output function
listf	equ	conoutf+3	;list output function
punchf	equ	listf+3		;punch output function
readerf	equ	punchf+3	;reader input function
homef	equ	readerf+3	;disk home function
seldskf	equ	homef+3		;select disk function
settrkf	equ	seldskf+3	;set track function
setsecf	equ	settrkf+3	;set sector function
setdmaf	equ	setsecf+3	;set dma function
readf	equ	setdmaf+3	;read disk function
writef	equ	readf+3		;write disk function
liststf	equ	writef+3	;list status function
sectran	equ	liststf+3	;sector translate
;
;	xios access table
xiosms	equ	sectran+3	;memory select / protect
xiospl	equ	xiosms+3	;device poll
strclk	equ	xiospl+3	;start clock
stpclk	equ	strclk+3	;stop clock
exitr	equ	stpclk+3	;exit critical region
maxcns	equ	exitr+3		;max console #
syinitf	equ	maxcns+3	;MP/M system initialization
;
	end
