; **** SUPERVISOR ****
boot	equ	0000h	; system reboot
bdos	equ	0005h	; bdos entry point
fcb	equ	005ch	; -> Primary File Control Block
ctl	equ	01d0h	; -> System Control Block
ps	equ	0c3fch	; SP save area & stack for printer interrupt
count	equ	0e7fch	; Seconds Counter
tick	equ	0e7ffh	; Slow Timer Status
kbsw	equ	0fe52h	; Keyboard switch status
attr	equ	0fe7ah	; VDU character attributes
;
; Z80 OP Codes--
ldir	equ	0b0edh
djnz	equ	00010h
;
;  Significant ASCII characters--
nul	equ	00h
etx	equ	03h
bel	equ	07h
bs	equ	08h
lf	equ	0ah
ff	equ	0ch
cr	equ	0dh
dc3	equ	13h	; [PAUSE] key
esc	equ	1bh
time	equ	7fh
s	equ	80h
;
; Define External Task locations--
tasku	equ	01000h	; System Utilities
tasko	equ	01C00h	; Options
taski	equ	02000h	; Initial Task
tasky	equ	05000h	; non-resident taskm overlay area
name	equ	07C00h	; Job Text area
taskx	equ	0E000h	; OS Utilities
ev0	equ	0E701h	; 1st Event Control Block
stack	equ	0E7C0h	; Scheduler Stack: Ready Count, ROC, -> Runner
rdy0	equ	stack+4 ; Ready Task Q
;
; Allocate Input Buffers--
bufe	equ	0d000h
buf0	equ	bufe-2048	; Com0 Input Buffer
buf3	equ	buf0-512	; Com3 Input Buffer
buf4	equ	buf3-512	; Com4 Input Buffer
;
	org	100h
	call	init !jmp go
; External entry points to Supervisor Services--
	jmp	stop	; Terminate Program
	jmp	suspend ; Block Task voluntarily
	jmp	char	; Keystroke -> A
vdu	jmp	rtn	; A -> Screen
	jmp	test0	; Z: Com0 -> A
	jmp	out0	; A -> Com0
	jmp	in3	; Com3 -> A
	jmp	out3	; A -> Com3
	jmp	in4	; Com4 -> A
	jmp	out4	; A -> Com4
	jmp	rtn	; MOUT Mainframe Output Driver (option)
testk	jmp	rtn	; Z: Keystroke -> A
	jmp	listen3 ; Z: Com3 -> A
	jmp	listen4 ; Z: Com4 -> A
io	jmp	rtn	; Screenhandler
clock	jmp	rtn	; Date & Time -> String @ DE
	jmp	rtn	; OUTPUT String (HL) -> Mainframe
pout	jmp	outl	; A -> Logging Printer
	jmp	fetch	; Overlay (HL) -> (DE)
stow	jmp	rtn	; STOW Write System Control Record
	jmp	rtn	; SPOOL (DE) -> Next Sector
	jmp	rtn	; UNSPOOL Oldest Sector -> (DE)
	jmp	spawn	; Initiate Task at (DE)
	jmp	timer	; Slow Timer Interrupt after DE units
	jmp	rtn	; SCREEN A -> Mainframe Terminal Screen
	jmp	rtn	; KYBD Translate A to M18 code
	jmp	rtn	; USER Keyboard Exit Routine
	jmp	open3	; Open Com3 Port
	jmp	close3	; Close Com3 Port
	jmp	open0	; Open Com0 Port
	jmp	open4	; Open Com4 Port
	jmp	sleep	; Suspend for DE seconds
	jmp	idler	; Suspend taskm with escape option
	jmp	taskm	; Mainframe Task
input	jmp	rtn	; Mainframe String -> (HL)
	jmp	spawni	; Initiate & count Task at (DE)
echo	jmp	rtn	; A -> Mainframe Electronic Mode
	jmp	openf	; Open fcb (DE) with name (HL)
	jmp	closef	; Close fcb (DE)
	jmp	rtn	; RESET Disc System
	jmp	trace	; A -> Screen if [SF1] lit
	jmp	rtn	; EXITM (Terminate Mainframe Job)
	jmp	bmap	; Map A buffers each of BC bytes at (HL)-2
	jmp	print	; Print Line
	jmp	cboot	; Cold Start
term	jmp	rtn	; Mainframe Terminal kybd task
	jmp	rtn	; MARK
	jmp	rtn	; ERROR
	jmp	rtn	; BYTE (Next IBMpc file byte -> A, or Z=EOF)
	jmp	wait	; Block Task until Event (DE)
ready	jmp	rtn	; Unblock Task awaiting Event (HL) (Int Off)
waitp	jmp	rtn	; Block Printer Channel Prog until interrupt
	jmp	rtn	; INJECT (HL) -> Mainframe (terminal)
	jmp	rtn	; NEXTDIR (HL)=Next IBM Directory entry, or Z=no match
	jmp	rtn	; Z=Password Correct
	jmp	rtn
	jmp	rtn
;
	org	1c0h
cword	db	0	; Pending Control Code
key	db	s	; current Keystroke
label	dw	0	; -> Spool Diskette Label
	dw	0	; (not used)
kew	dw	kev0+1	; -> current Keyboard Event Word
mname	dw	name	; -> taskm current Electronic pgm name
mask0	db	0	; Com0 Data Mask
mask3	db	0	; Com3 Data Mask
mask4	db	0	; Com4 Data Mask
	db	0	; (spare)
config	db	1	; B0: Parallel printer available
			; B1: Com3 & Com4 (Telecomms) available
			; B2: Mainframe Emulator running
			; B3: Mainframe Kybd Task running
			; B7: Autodial Modem
swreg	db	0	; initial Switch Register mask
;
; System Control Block--
	org	ctl
hstate	db	0	; hstate (HX20 task idle)
	db	0,0,0,0,0,0,0
	dw	08000h	; -> Record Area
	dw	64	; = Record Length (bytes)
mstate	db	0,0	; mstate, mlines
	dw	0,0	; mtimer,
tstate	db	0	; B7: [BREAK] pressed
	dw	name+40h; -> A/C name & address
msub	db	0	; Mainframe subtask count
	db	0	; Telecomms subtask count
	db	0,0	; xstate
light	db	0	; Cursor Control
	dw	0,0,0,0,0,0,0,0,0,0,0
;
; Buffer Control--
	dw	buf4,buf3,buf0,bufe  ; -> Input Buffers
put4	dw	buf4,buf4	     ; put4, get4
put3	dw	buf3,buf3	     ; put3, get3
put0	dw	buf0,buf0	     ; put0, get0
;
; ******************* Task Scheduler **********************
suspend push	psw !push b !push h	; Block Task voluntarily
su0	dw	073edh,0 ; LD (0),SP
go	lxi	sp,stack !di !pop b !pop h ; B=ROC, C=Ready Count, HL -> Run
	inx	h !inx h !dcr b !jnz $+7 !mov b,c !lxi h,rdy0 ; wrap around
	push	h !push b !ei !shld su0+2 !shld go0+2
go0	dw	07bedh,0 ; LD SP,(0)	; next Task SP
	pop	h !pop b !pop psw
rtn	ret	; Schedule next Task
;
wait	push	psw !push b !push h	; Block Task until Event (DE)
	xchg	!di !mov a,m !mvi m,0ffh !cpi 80h !jz su0 !dcx h
block	shld	$+5 !dw 073edh,0 ; LD ((HL)),SP ; Remove Task from Ready Q
	lxi	sp,stack !di !pop b !pop d ; B=ROC, C=Ready Count, DE -> Runner
	dcr	c !lxi h,-2 !dad d !push h !push b !cz halt !dcr b !jz go
	lxi	h,2 !dad d		; Shunt Ready Q left 1 entry
	mov	c,b !mvi b,0 !dw 021cbh,ldir ; SLA C ; LDIR
	jmp	go
halt	ei	!hlt !di !lda stack !ora a !rnz !jmp halt
;
spawni	shld	savehl !lxi h,msub !inr m !lxi h,ttermi !jmp sp1
spawn	shld	savehl !lxi h,tterm	; Create Task with entry point (DE)
sp1	push	h !lhld free !shld sp2+6 !inx h !inx h !shld free !pop h
sp2	dw	073edh,savesp,07bedh,0 ; LD (savesp),SP ; LD SP,(0)
	push	h !lhld savehl !push d !push psw !push b !push h
	dw	073edh,savehl,07bedh,savesp ; LD (savehl),SP ; LD SP,(savesp)
	push	h !push psw !lxi h,savehl+1
	di	!call ready !ei !pop psw !pop h !ret
;
ttermi	lxi	h,msub !dcr m
tterm	lhld	free !dcx h !dcx h !shld free !jmp block ; Terminate Task
;
free	dw	rdy0+2			; -> next free stack area
savesp	ds	2
savehl	ds	2
;
;
in3	call	test3 !rz !call suspend !jmp in3 ; Com3 -> A
listen3 call	suspend !jmp test3	; Z: Com3 -> A
;
in4	call	test4 !rz !call suspend !jmp in4 ; Com4 -> A
listen4 call	suspend !jmp test4	; Z: Com4 -> A
;
om0	call	suspend
out0	mov	e,a !in 13h !ani 4 !mov a,e !jz om0 ; wait for Tx empty
	out	11h !ret
;
oh0	call	suspend
out3	mov	e,a !in 0c5h !ani 4 !mov a,e !jz oh0 ; wait for Tx empty
	out	0c4h !push h !lxi h,kbsw !dw 05ecbh ; BIT 3,(HL) ; [SF1]
	cnz	tlo !pop h !ret
tlo	lxi	h,attr !dw 056cbh,096cbh ; BIT 2,(HL) ; RES 2,(HL)
	push	psw !ori s !call vdu !pop psw !rz !dw 0d6cbh ; SET 2,(HL)
	ret
;
od0	call	suspend
out4	mov	e,a !in 0c7h !ani 4 !mov a,e !jz od0 ; wait for Tx empty
	out	0c6h !ret
;
ol0	call	suspend
outl	mov	e,a !in 15h !ani 20h !mov a,e !jnz ol0 ; not ready
	out	14h !xra a !out 17h !inr a !out 17h ; strobe
	mov	a,e !ret
;
test0	push	h !lhld put0+2 !xchg !lhld put0 !ora a !dw 052edh ; SBC HL,DE
	jnz	tm1 !inr h !pop h !ret		; Z=0 (no data)
tm1	ldax	d !inx d !lxi h,bufe !ora a !dw 052edh ; SBC HL,DE
	jnz	$+6 !lxi d,buf0 !xchg !shld put0+2
	pop	h !cmp a !ret			; Z=1 (data)
;
test3	push	h !lhld put3+2 !xchg !lhld put3 !ora a !dw 052edh ; SBC HL,DE
	jnz	th1 !inr h !pop h !ret		; Z=0 (no data)
th1	ldax	d !inx d !lxi h,buf0 !ora a !dw 052edh ; SBC HL,DE
	jnz	$+6 !lxi d,buf3 !xchg !shld put3+2
	lxi	h,kbsw !dw 05ecbh ; BIT 3,(HL)
	cnz	thi !pop h !cmp a !ret		; Z=1 (data)
thi	lxi	h,attr !dw 056cbh,0d6cbh ; BIT 2,(HL) ; SET 2,(HL)
	push	psw !ori s !call vdu !pop psw !rnz !dw 096cbh ; RES 2,(HL)
	ret
;
test4	push	h !lhld put4+2 !xchg !lhld put4 !ora a !dw 052edh ; SBC HL,DE
	jnz	td1 !inr h !pop h !ret		; Z=0 (no data)
td1	ldax	d !inx d !lxi h,buf3 !ora a !dw 052edh ; SBC HL,DE
	jnz	$+6 !lxi d,buf4 !xchg !shld put4+2
	pop	h !cmp a !ret			; Z=1 (data)
;
close3	mvi	c,0c5h				; Com3
close	mvi	a,18h !dw 079edh ; OUT (C),A	; Channel Reset
	ret
;
open0	push	h !xchg !di			; RS232 Com0
	mvi	c,06h !mvi a,0b6h !di !out 07h	; Counter 2 Square Wave
	lxi	h,rate !call start+3 !mvi a,18h !out 13h ; Channel Reset
	mvi	a,2 !out 13h !xra a !out 13h	; WR2B
	in	0cch !ani 40h !push psw 	; Isolate Com4 notDSR
	mvi	c,013h !call setup0 !sta mask0
	in	0cch !ani 40h !mov c,a
	pop	psw !xra c !pop h !rz		; no change in Com4 DSR
open4	xchg	!di				; RS232 Com4
	mvi	c,0c9h !mvi a,076h !out 0cbh !call start ; Counter 1
	mvi	c,0c7h !call setup !sta mask4 !ret ; Z=0
;
open3	xchg	!di				; RS232 Com3
	mvi	c,0cah !mvi a,0b6h !out 0cbh !call start ; Counter 2 (Tx)
	mvi	c,0c8h !mvi a,036h !out 0cbh !call start ; Counter 0 (Rx)
	mvi	c,0c5h !call setup !sta mask3 !ret
;
setup	mvi	a,18h !dw 079edh ; OUT (C),A	; Channel Reset
	mvi	a,2 !out 0c5h !xra a !out 0c5h	; WR2A
	mvi	a,2 !out 0c7h !xra a !out 0c7h	; WR2B
setup0	ldax	d !inx d !ani 3 !mov b,a	; Bits per Char
	jz	$+5 !cpi 3 !jz $+5 !xri 3 !rrc !rrc !mov l,a ; bits/c mask
	mvi	a,0fh !rlc !dcr b !jp $-2 !ori 0fh !push psw ; save data mask
	ldax	d !inx d !ani 3 !mov b,a	; Parity
	ldax	d !inx d !ani 3 !rlc !rlc	; Stop Bits
	ora	b !ori 40h !sta cmnd+1		; Clock x16
	ldax	d !ani 20h !ori 1 !ora l !mov h,a !sta cmnd+7 ; WR3
	ldax	d !ani 3 !dw 0dcbh,047cbh ; RRC L ; BIT 0,A
	jz	$+5 !ori 80h !ani 82h !ori 8 !ora l !mov l,a !sta cmnd+5 ; WR5
	xchg	!lxi h,cmnd !mvi b,8 !dw 0b3edh ; OTIR ; WR4, WR1, WR5, WR3
	ei	!pop psw !ret ; A=data mask, D=WR3, E=WR5
cmnd	db	4,000h,1,010h,5,000h,3,000h
;
start	lxi	h,rate+2			; Start Counter
	ldax	d !inx d !rlc !rlc !push b !mvi b,0 !mov c,a !dad b !pop b
	mvi	b,2 !dw 0b3edh ; OTIR
	ret
;
trace	push	psw !push h !lxi h,kbsw !dw 05ecbh ; BIT 3,(HL)
	pop	h !cnz vdu !pop psw !ret
;
pr0	call	suspend
print	lda	pfree !inr a !jnz pr0 !sta pfree
	lxi	d,pdriver !dw 073edh,ps+2 ; LD (ps+2),SP ; Start Driver
	lxi	sp,ps !push d !push h !push b ; pass HL, BC to Driver DE
	dw	073edh,ps,07bedh,ps+2 ; LD (ps),SP ; LD SP,(ps+2)
	mvi	a,0dh !out 17h		; printer interrupt ON
	lxi	d,ev0+4 !call wait !lxi h,pfree !mvi m,0ffh !lhld now !ret
pfree	db	0ffh
;
; Printer Channel Program (keep off BC)--
pdriver dw	07ecbh ; BIT 7,(HL)	; test for embedded control byte
	jz	$+7 !mov d,m !inx h !dw 0bacbh ; RES 7,D ; pickup control byte
	dcr	d !jpe itext !cnz feed !call text
	mvi	a,lf !call strobe !mvi a,cr !call strobe
pdone	shld	now !lxi h,ev0+4 !di !call ready !jmp waitp ; done
;
feed	mvi	a,ff !jm strobe
fe1	mvi	a,lf !call strobe !dcr d !rz !jmp fe1
;
itext	mov	a,m !inx h !ora a !jz pdone !call strobe !jmp itext
te0	call	strobe
text	mov	a,m !inx h !ora a !rz
	cpi	cr !jz $+5 !cpi lf !jnz $+5 !mvi a,' ' !cpi time !jnz te0
	lxi	d,now !call clock !push h !lxi h,now !mvi e,22
te1	mov	a,m !inx h !call strobe !dcr e !jnz te1 !pop h !jmp text
strobe	out	14h !xra a !out 17h !inr a !out 17h ; data & strobe
	mvi	a,0dh !di !out 17h !jmp waitp ; printer interrupt ON
;
; Read Overlay (HL) into (DE)--
fetch	mvi	a,0c9h !stax d !push d		; Preset RET instr.
	lxi	d,fcb !lxi b,12 !dw ldir	; Title -> FCB
	lxi	h,fcb+32 !xra a !mov m,a	; Current Record=0
	lxi	d,fcb !mvi c,15 !call bdos	; Open File for Input
	pop	d !cpi 255 !rz			; Overlay not found
; Load code from file--
f2	lxi	h,128 !dad d !push h		; Update DMA pointer
	mvi	c,26 !call bdos 		; Set DMA Address
	lxi	d,fcb !mvi c,20 !call bdos	; Read Sector
	pop	d !cpi 0 !jz f2 !ret
;
; Open .$$$ file with fcb (DE) and name (HL)--
openf	push	d !lxi b,9 !dw ldir
	push	h !lxi h,sss !lxi b,3 !dw ldir
	mov	h,d !mov l,e !mvi m,0 !inx d !lxi b,20 !dw ldir ; zeroise fcb
	pop	h !lxi b,3 !dw ldir		; save type suffix
	pop	d !push d !mvi c,19 !call bdos	; delete any previous work file
	pop	d !mvi c,22 !call bdos		; enter in directory
	inr	a !ret				; Z=directory full
; Close work file with fcb (DE)--
closef	push	d !mvi c,16 !call bdos		; close file
	pop	d !push d !lxi h,9 !dad d !xchg !lxi h,bak !lxi b,3 !dw ldir
	pop	d !push d !mvi c,19 !call bdos	; delete old .BAK
	pop	d !push d !lxi h,16 !dad d !xchg !lxi b,16 !dw ldir
	pop	h !push h !lxi b,9 !dad b !xchg !inx h !lxi b,3 !dw ldir
	pop	d !push d !mvi c,23 !call bdos	; rename old .xxx as .BAK
	pop	d !push d !lxi h,16 !dad d !xchg !lxi b,16 !dw ldir
	pop	d !push d !lxi h,9 !dad d !xchg !lxi h,sss !lxi b,3 !dw ldir
	pop	d !mvi c,23 !jmp bdos		; rename .$$$ as .xxx
sss	db	'$$$'
bak	db	'BAK'
;
; Map A buffers each of BC bytes at (HL)-2 using 6+A*(BC+2) bytes--
bmap	mov	d,h !mov e,l !dcx h !mov m,d !dcx h !mov m,e !xchg
	mvi	m,0 !inx h !mov m,a !inx h !xchg
	mvi	h,0 !mov l,a !dad h !inx h !inx h !dad d
bm1	xchg	!mov m,e !inx h !mov m,d !inx h !xchg !dad b
	dcr	a !jnz bm1 !stax d !inx d !stax d
	inx	h !inx h !ret
;
; Set Slow Timer to interrupt after DE units--
timer	xra	a !sta tick
	mov	a,e !out 1 !mov a,d !out 1 !ret
;
; Suspend task for DE seconds--
sleep	push	psw !push h !ora a !lxi h,0 !dw 052edh	; SBC HL,DE
	shld	count !pop h
sl10	call	suspend !lda count+1 !ora a !jm sl10
	pop	psw !ret
;
puc	mov	a,m !ora a !jnz $+6 !mvi a,' ' !ret !inx h
uc	cpi	'a' !rc !cpi 'z'+1 !rnc !sui 20h !ret ; upper case
;
con	lxi	h,light !dcr m !lxi h,csw !jmp io ; cursor on
coff	lxi	h,light !inr m !lxi h,csw !jmp io ; cursor off
;
led	push	psw !in 12h !ani 4 !jz led+1 !pop psw !out 10h !ret
;
ddt	lhld	0006h !lxi d,0d000h !ora a !dw 052edh ; SBC HL,DE
	ret
;
hl	pchl
;
stop	push	h !call wrapup !mvi a,0c9h !sta 0109h ; disable Suspend rtn
	pop	h !call io !jmp boot
;
cboot	lda	mstate !ani 1 !cnz tmode !ora m !mov m,a
	lxi	d,80h !lxi b,16 !dw ldir
	call	wrapup !lxi d,8100h !lxi h,gofile !call fetch
	lxi	d,8000h !lxi h,code !lxi b,32 !dw ldir
	jmp	8000h
tmode	push	h !lhld mname !lxi d,90h !lxi b,4 !dw ldir ; save pgm name
	lxi	h,mstate !dw 0e6cbh ; SET 4,(HL)
tr1	call	suspend !dw 046cbh ; BIT 0,(HL) ; wait for Terminal Mode
	jnz	tr1 !call suspend !mvi a,80h !pop h !ret
code	lxi	d,0100h !lxi h,8100h !lxi b,0f00h !dw ldir
	jmp	0100h
;
wrapup	mvi	c,013h !call close !mvi c,0c7h !call close !call close3 ; 0,4,3
	mvi	e,0ah !call wclock	; disable clock interrupts
	lhld	masko !mov a,h !out 09h !mov a,l !out 0dh ; restore Epson mask
	in	34h !ani 1fh !jnz $-4	; FDC busy
	lxi	h,0fc02h !shld 0fd9ah	; Restore Epson FDC interrupt rtn
	lxi	h,0fbfdh !shld 0fd92h	; Restore Epson SIO interrupt rtn
	lxi	h,epson !lxi d,0fda0h !lxi b,32 !dw ldir ; restore int vector
	ret
;
wclock	mvi	a,10 !out 3dh !in 3ch !ora a !jm wclock ; update in progress
	mvi	a,11 !out 3dh !mov a,e !out 3ch !ret	; write RAM byte 0bh
;
epson	ei	!jmp 0fc30h		; Printer
	push	h !jmp 0fc16h		; Option Slot 1
	nop	!jmp 0fc32h		; Clock
	push	h !jmp 0fc1bh		; Option Slot 2
	push	h !jmp 0fc20h		; Option Slot 3
	ei	!jmp 0fc31h		; Software Timer (slow)
	push	h !jmp 0fc25h		; Option Slot 4
	push	h !jmp 0fc2ah		; Option Slot 5
;
; RS232 Clock:	MAIN  OPTION
rate	dw	09c0h,0780h   ;  0    50 Baud
	dw	0680h,0500h   ;  1    75 Baud
	dw	046fh,0369h   ;  2   110 Baud
	dw	039ch,02c7h   ;  3   135 Baud
	dw	0340h,0280h   ;  4   150 Baud
	dw	0270h,01e0h   ;  5   200 Baud
	dw	01a0h,0140h   ;  6   300 Baud
	dw	0138h,00f0h   ;  7   400 Baud
	dw	00d0h,00a0h   ;  8   600 Baud
	dw	008bh,006bh   ;  9   900 Baud
	dw	0068h,0050h   ; 10  1200 Baud
	dw	0045h,0035h   ; 11  1800 Baud
	dw	0034h,0028h   ; 12  2400 Baud
	dw	001ah,0014h   ; 13  4800 Baud
	dw	000dh,000ah   ; 14  9600 Baud
	dw	0006h,0005h   ; 15 19200 Baud
;
; *********************** Mainframe Task ***********************
;
taskm	dw	073edh,msp ; LD (msp),SP
	mov	e,m !inx h !mov d,m !inx h !shld list ; -> Mainframe rtns
	lxi	h,rtn !mov a,d !ora e !jz $+4 !xchg !push h ; -> Emulator
	lxi	h,mparms !lda swreg !dw 057cbh ; BIT 2,A ; SW3 (4800 baud)
	jz	$+5 !mvi m,0dh !inx h !dw 047cbh ; BIT 0,A ; SW1 (8 N)
	jz	$+5 !mvi m,3 !inx h !ani 3 !xri 3 !mov m,a !dcx h !dcx h
	call	open0 !pop d !jz m01		; Emulator not connected
	call	spawn !lxi h,config !dw 0d6cbh ; SET 2,(HL)
m01	lhld	term+1 !mov a,m !cpi 0c9h !jz m06 ; immediate ret instruction
	lxi	h,config !dw 0decbh ; SET 3,(HL); Mainframe Kybd running
	lxi	d,term !call spawn		; Mainframe Terminal kybd
m06	call	off !call prog !shld fn 	; wait for electronic pgm
	call	on !lxi h,mstate !dw 0c6cbh	; SET 0,(HL); block KYBD
m08	call	suspend !lda mstate !ani 10h !jnz i10
	lxi	h,msub !mov a,m !ora a !jnz m08 ; previous job incomplete
	inr	m !lhld fn !call hl		; Go
	lxi	h,msub !dcr m			; terminated
	lda	mstate !ani 01h !jnz m08 !jmp m06
;
off	lda	config !ani 8 !cnz con !mvi a,44h !jmp led ; off-line
on	lda	config !ani 8 !cnz coff !mvi a,45h !jmp led ; on-line
;
idler	lda	mstate !ani 10h !jz suspend !lxi h,msub !dcr m
; Revert to Terminal Mode--
i10	lda	mstate !ani 0eeh !sta mstate	; B0, B4 off
	mvi	a,esc !call echo !dw 07bedh,msp ; LD SP,(msp)
	jmp	m06
;
prog	lhld	mname !call input
	lhld	mname !lxi d,pgm+1 !lxi b,4 !dw ldir
; Scan name table--
	lhld	list
t40	mov	a,m !ora a !jz link		; not in list
	xchg	!push d !call match !pop d !rz
	lxi	h,6 !dad d !jmp t40		; try next entry
; Fetch and link to overlay--
link	lxi	h,pgm !lxi d,tasky !call fetch !lxi h,tasky !ret
; Test name against table entry--
match	lxi	h,pgm+1 !mvi b,4
m90	ldax	d !cmp m !inx d !inx h !rnz !dw djnz+(m90-$-2)*256
	ldax	d !mov l,a !inx d !ldax d !mov h,a !ret
;
; ********************* Keyboard Task ***********************
taskk	call	chr !sta key !lhld kew !di !call ready !ei ; unblock user task
	lxi	h,key !mvi a,s !mvi b,16 ; B=timer limit
tk1	call	suspend !cmp m !jz taskk !dw djnz+(tk1-$-2)*256
	mov	m,a !mvi a,bel !call vdu !jmp taskk ; discard (timed out)
;
char	push	h !lhld kew !push h !inx h !inx h !shld kew
ch1	lhld	kew !xchg !call wait !lxi h,key !mov a,m !cpi s !jz ch1
	mvi	m,s !pop h !shld kew !pop h !ret
;
kev0	dw	0ffffh,0ffffh,0ffffh,0ffffh,0ffffh ; Keyboard Event list
;
debug	lxi	h,0109h !mvi m,0c9h	; disable Suspend Rtn
	call	con !lxi h,01c0h !call 38h !call coff ; ddt
	lxi	h,0109h !mvi m,0c3h	; enable Suspend Rtn
chr	call	ink !cpi dc3 !jz opt	; [OPTION] key
	cpi	etx !rnz		; [BREAK] key
	call	ddt !jz debug !lda tstate !ori 80h !sta tstate !jmp chr
;
opt	lxi	h,light !mov a,m !push psw !mvi m,0 !lxi h,msg2 !call io
	call	ink !call uc !sta cword !sta msg3+4
	pop	psw !sta light !lxi h,msg3 !call io !lda cword
	cpi	'X' !lxi h,msg0 !jz stop
	cpi	'Q' !cz queue !jmp chr
ink	call	testk !rz !lxi d,ev0+6 !call wait !jmp ink
;
queue	xra	a !sta cword !lxi h,mstate !dw 046cbh ; BIT 0,(HL)
	mvi	a,esc !jz echo		; Terminal Mode
	dw	0e6cbh ; SET 4,(HL)	; request Terminal Mode
	call	suspend !dw 0a6cbh,046cbh ; RES 4,(HL) ; BIT 0,(HL)
	rz	!mvi a,bel !jmp vdu
;
; ************** Initial Task Control Program ***************
tcpi	push	h !lxi h,form0 !call io !pop h !call io
	call	taski !lxi h,null !call taskm !jmp stop
;
printx	xra	a !lxi b,0 !dw 0b1edh ; CPIR	; null print routine
	ret
;
; ************************ Initiator ************************
init	in	18h !sta swreg !call ddt	; Z=debug running
	lxi	h,80h !jnz $+8 !xra a !mov m,a !inx h !mov m,a !dcx h
	call	iname
	lxi	h,ev0-1 !mvi m,0ffh !lxi d,ev0 !lxi b,191 !dw ldir ; events
	lxi	d,stack !lxi h,work !lxi b,30 !dw ldir	; initialize Qs
	in	09h !mov h,a !in 0dh !mov l,a !shld masko ; initial mask
	lxi	h,ivec !lxi d,0fda0h !lxi b,32 !dw ldir ; interrupt vector
	mvi	a,'X' !lxi d,taskx !call load	; OS Utilities
	mvi	a,'U' !lxi d,tasku !call load	; System Utilities
	mvi	a,'O' !lxi d,tasko !call load	; Options
	call	taskx !call tasku !call tasko	; Patch BIOS, OS, Options
	lxi	h,0 !shld count !shld count+2
	mvi	e,03ah !call wclock		; enable clock interrupts
	mvi	a,070h !out 3 !sta tick 	; Initialize Slow Timer
	mvi	a,00ch !out 17h 		; disable printer interrupts
	lhld	mask !mov a,h !out 09h !mov a,l !out 0dh ; setup int mask
	out	0cch !mvi a,8 !dcr a !jnz $-1	; Find Aux RS232 card
	lhld	vect !cmp h !jz i4		; not found
	dcx	h !dcx h !dcx h !mov a,l !sui 09ch !rrc !rrc
	mov	b,a !mvi a,80h !rlc !dcr b !jnz $-2 ; set Slave Mask bit in A
	xchg	!lxi h,aux !lxi b,4 !dw ldir	; install interrupt vector
	lxi	h,config !dw 0cecbh ; SET 1,(HL); Com3 & Com4 available
i4	mov	b,a !lda mask !ori 0dah !xra b !out 0dh ; mask other slots
	lxi	h,ifile !lxi d,taski !call fetch
	lxi	d,taskk !call spawn		; Keyboard Task
	lxi	d,tcpi !lxi h,csw		; Initial Task
	in	15h !ani 68h !cpi 48h !jz spawn ; printer ready
	lxi	h,msg7 !cpi 68h !jnz spawn	; printer not ready
	mvi	a,0c9h !sta pout !lxi h,printx !shld 0188h
	lxi	h,config !dw 086cbh ; RES 0,(HL); no parallel printer
	lxi	h,msg6 !jmp spawn
;
aux	push	h !jmp 0e003h
trap	push	psw !in 0cch !pop psw !xthl !shld vect !xthl !ei !ret
vect	dw	0
;
load	lxi	h,file+1 !mov m,a !dcx h !call fetch !rnz
	lxi	d,msg1 !mvi c,9 !call bdos !jmp boot
;
iname	mov	a,m !ani 7fh !rz !lxi d,ifile+1 !mvi b,8
i1	inx	h !mov a,m !cpi ' ' !jz i1	; skip spaces
i2	call	puc !stax d !inx d !dw djnz+(i2-$-2)*256
	ret
;
mparms	db	0eh,2,3,1,0dfh	; 9600 7 E 1
form0	db	1,1,0e2h,'Joe',27h,'s OS V72 ',7fh,s,3,1,nul
null	db	nul
csw	db	0,0,nul 	; Cursor Switch string
msg0	db	0,1,0c0h,time,'  OS Shutdown',nul
msg1	db	cr,lf,'Cannot find X.OVL, U.OVL &/or O.OVL$'
msg2	db	1,28,91h,'  Option:   ',bs,bs,bs,nul
msg3	db	1,36,81h,'= ',nul
msg6	db	1,40,81h,'No Printer',nul
msg7	db	1,40,84h,'Printer unready',nul
file	db	0,'        OVL'
ifile	db	0,'I       OVL'
gofile	db	0,'GO      COM'
pgm	db	0,'xxxx    OVL' ; Main Electronic Overlay name
mask	dw	02e00h
;
masko	ds	2	; original interrupt mask
list	ds	2	; -> taskm resident pgm name/address table
fn	ds	2	; -> taskm current Electronic pgm
msp	ds	2	; taskm save SP
now	ds	22	; Printer Driver w/s
; Stack Control (12 Task stacks each of 30 levels)--
work	dw	0100h,rdy0-2		; Task Ready Count, ROC, -> Runner
	dw	0,work+60*1,work+60*2,work+60*3,work+60*4
	dw	work+60*5,work+60*6,work+60*7,work+60*8
	dw	work+60*9,work+60*10,work+60*11,work+60*12
ivec	push	h !jmp 0		; Printer
	call	trap !ret		; Option Slot 1
	push	psw !jmp 0fc32h 	; Clock
	call	trap !ret		; Option Slot 2
	call	trap !ret		; Option Slot 3
	push	psw !jmp 0fc32h 	; Software Timer (slow)
	call	trap !ret		; Option Slot 4
	call	trap !ret		; Option Slot 5
	end

The QX10 Archive