	title	'MP/M II V2.0  DSC-2 Basic & Extended I/O Systems'
	cseg

false	equ	0
true	equ	not false

	maclib	z80

Banked	equ	false
;Banked	equ	true

debug	equ	true
;debug	equ	false

;ldcmd	equ	true
ldcmd	equ	false
;
; disk io is in separate module

	extrn	home,seldsk,settrk,setsec,setdma,read,write,sectran

	public	swtuser,swtsys,pdisp,xdos,sysdat

;bios jump vector table

	jmp	commonbase
wboot:
	jmp	warmstart	;warm start
	jmp	const		;console status
	jmp	conin		;console character in
outCH:	jmp	conout		;console character out
	jmp	list		;list character out
	jmp	rtnempty	;punch not implemented
	jmp	rtnempty	;reader not implemented
	jmp	home		;move head to home
	jmp	seldsk		;select disk
	jmp	settrk		;set track number
	jmp	setsec		;set sector number
	jmp	setdma		;set dma address
	jmp	read		;read disk
	jmp	write		;write disk
	jmp	listst		;list status
	jmp	sectran		;sector translate

	jmp	selmemory	; select memory
	jmp	polldevice	; poll device
	jmp	startclock	; start clock
	jmp	stopclock	; stop clock
	jmp	exitregion	; exit region
	jmp	maxconsole	; maximum console number
	jmp	systeminit	; system initialization
	db	0,0,0		; force use of internal dispatch @ idle
;	jmp	idle		; idle procedure
;
commonbase:
	 jmp	coldstart
swtuser: jmp	$-$
swtsys:  jmp	$-$
pdisp:   jmp	$-$
xdos:	 jmp	$-$
sysdat:  dw	$-$

coldstart:
warmstart:
	mvi	c,0
	jmp	xdos		; system reset, terminate process


;I/O handlers
;
;
;  MP/M II V2.0   Console Bios
;
;
nmbcns	equ	4	; number of consoles

poll	equ	131	; XDOS poll function
makeque	equ	134	; XDOS make queue function
readque	equ	137	; XDOS read queue function
writeque equ	139	; XDOS write queue function
xdelay	equ	141	; XDOS delay function
create	equ	144	; XDOS create process function

plco0	equ	0	; poll console out #0
plco1	equ	1	; poll console out #1
plco2	equ	2	; poll console out #2
plco3	equ	3	; poll console out #3 
plco4	equ	4	; poll console out #4
plco5	equ	5	; poll console out #5
plco6	equ	6	; poll console out #6
plco7	equ	7	; poll console out #7 
plci0	equ	8	; poll console in #0
plci1	equ	9	; poll console in #1
plci2	equ	10	; poll console in #2 
plci3	equ	11	; poll console in #3
plci4	equ	12	; poll console in #4
plci5	equ	13	; poll console in #5
plci6	equ	14	; poll console in #6 
plci7	equ	15	; poll console in #7
pllpt0	equ	16	; poll printer #0
pllpt1	equ	17	; poll printer #1

;
const:			; Console Status
	call	ptbljmp	; compute and jump to hndlr
	dw	pt0st	; console #0 status routine
	dw	pt1st	; console #1 status rt
	dw	pt2st	; console #2 status rt
	dw	pt3st	; console #3 status rt

conin:			; Console Input
	call	ptbljmp	; compute and jump to hndlr
	dw	pt0in	; console #0 input
	dw	pt1in	; console #1 input
	dw	pt2in	; console #2 input
	dw	pt3in	; console #3 input

conout:			; Console Output
	call	ptbljmp	; compute and jump to hndlr
	dw	pt0out	; console #0 output
	dw	pt1out	; console #1 output
	dw	pt2out	; console #2 output
	dw	pt3out	; console #3 output

;
ptbljmp:		; compute and jump to handler
			; d = console #
			; do not destroy d !
	mov	a,d
	cpi	nmbcns
	jc	tbljmp
	pop	psw	; throw away table address
rtnempty:
	xra	a
	ret
tbljmp:			; compute and jump to handler
			; a = table index
	add	a	; double table index for adr offst
	pop	h	; return adr points to jump tbl
	mov	e,a
	mvi	d,0
	dad	d	; add table index * 2 to tbl base
	mov	e,m	; get handler address
	inx	h
	mov	d,m
	xchg
	pchl		; jump to computed cns handler

;
; ASCII Character Equates
;
uline	equ	5fh
rubout	equ	7fh
space	equ	20h
backsp	equ	8h
altrub	equ	uline
;
; Input / Output Port Address Equates
;
data0	equ	7ah	;crt
sts0	equ	data0+1
cd0	equ	sts0
data1	equ	7ch	;tty
sts1	equ	data1+1
cd1	equ	sts1
data2	equ	70h	;serial A
sts2	equ	data2+1
cd2	equ	sts2
data3	equ	72h	;serial b
sts3	equ	data3+1
cd3	equ	sts3

;POLL CONSOLE # 0 INPUT

polci0:
pt0st:			;TEST CONSOLE STATUS
	in	sts0
	ani	02h
	rz
	mvi	a,0ffh
	ret

;console # 0 input

pt0in:			;return char in reg a
	call	polci0	;is it ready now?
	ora	a
	jrnz	pt0in1	;if ready, skip poll
	mvi	c,poll
	mvi	e,plci0	;poll console #0 input
	call	xdos
pt0in1:
	in	data0		;read character
	ani	07fh		;strip parity
	ret

;console # 0 output 

pt0out:			;reg c = char to output
	call	polco0	;is it ready now?
	ora	a
	jrnz	pt0out1	;if ready, skip poll
	push	b
	mvi	c,poll
	mvi	e,plco0
	call	xdos	;poll console #0 output
	pop	b
pt0out1:
	mov	a,c
	out	data0	;transmit character
	ret

;poll console # 0 output

polco0:			;return offh if ready
	in	sts0
	ani	01h
	rz
	mvi	a,0ffh
	ret

;POLL CONSOLE # 1 INPUT

polci1:
pt1st:			;TEST CONSOLE STATUS
	in	sts1
	ani	02h
	rz
	mvi	a,0ffh
	ret

;console # 1 input

pt1in:			;return char in reg a
	call	polci1	;is it ready now?
	ora	a
	jrnz	pt1in1	;if ready, skip poll
	mvi	c,poll
	mvi	e,plci1	;poll console #1 input
	call	xdos
pt1in1:
	in	data1		;read character
	ani	07fh		;strip parity
	ret

;console # 1 output 

pt1out:			;reg c = char to output
	call	polco1	;is it ready now?
	ora	a
	jrnz	pt1out1	;if ready, skip poll
	push	b
	mvi	c,poll
	mvi	e,plco1
	call	xdos	;poll console #1 output
	pop	b
pt1out1:
	mov	a,c
	out	data1	;transmit character
	ret

;poll console # 1 output

polco1:			;return offh if ready
	in	sts1
	ani	01h
	rz
	mvi	a,0ffh
	ret

;POLL CONSOLE # 2 INPUT

polci2:
pt2st:			;TEST CONSOLE STATUS
	in	sts2
	ani	02h
	rz
	mvi	a,0ffh
	ret

;console # 2 input

pt2in:			;return char in reg a
	call	polci2	;is it ready now?
	ora	a
	jrnz	pt2in1	;if ready, skip poll
	mvi	c,poll
	mvi	e,plci2	;poll console #2 input
	call	xdos
pt2in1:
	in	data2		;read character
	ani	07fh		;strip parity
	ret

;console # 2 output 

pt2out:			;reg c = char to output
	call	polco2	;is it ready now?
	ora	a
	jrnz	pt2out1	;if ready, skip poll
	push	b
	mvi	c,poll
	mvi	e,plco2
	call	xdos	;poll console #2 output
	pop	b
pt2out1:
	mov	a,c
	out	data2	;transmit character
	ret

;poll console # 2 output

polco2:			;return offh if ready
	in	sts2
	ani	01h
	rz
	mvi	a,0ffh
	ret

;POLL CONSOLE # 3 INPUT

polci3:
pt3st:			;TEST CONSOLE STATUS
	in	sts3
	ani	02h
	rz
	mvi	a,0ffh
	ret

;console # 3 input

pt3in:			;return char in reg a
	call	polci3	;is it ready now?
	ora	a
	jrnz	pt3in1	;if ready, skip poll
	mvi	c,poll
	mvi	e,plci3	;poll console #3 input
	call	xdos
pt3in1:
	in	data3		;read character
	ani	07fh		;strip parity
	ret

;console # 3 output 

pt3out:			;reg c = char to output
	call	polco3	;is it ready now?
	ora	a
	jrnz	pt3out1	;if ready, skip poll
	push	b
	mvi	c,poll
	mvi	e,plco3
	call	xdos	;poll console #3 output
	pop	b
pt3out1:
	mov	a,c
	out	data3	;transmit character
	ret

;poll console # 3 output

polco3:			;return offh if ready
	in	sts3
	ani	01h
	rz
	mvi	a,0ffh
	ret

;
;
; Line Printer Driver:  z80 emulator
;
lptprt0	EQU	7eH		;PRINTER #0 DATA
lptsts0	EQU	lptprt0+l	;PRINTER #0 STATUS
lptprt1	EQU	7eH		;PRINTER #1 DATA
lptsts1	EQU	lptprt1+1	;PRINTER #1 STATUS

list:			; List Output
lp0out:			;reg c = char to output
	call	pollpt0	;is it ready now?
	ora	a
	jrnz	lp0out1	;if ready, skip poll
	push	b
	mvi	c,poll
	mvi	e,pllpt0
	call	xdos	;poll lpt #0 output
	pop	b
lp0out1:
	mov	a,c
	out	lptprt0	;transmit character
	ret

;poll lpt # 0 output
listst:
pollpt0:			;return offh if ready
	in	lptsts0
	ani	01h
	rz
	mvi	a,0ffh
	ret
;
;
;
;  MP/M II V2.0   Xios
;
;
polldevice:
			; Reg C = device # to be polled
			; return 0ffh if ready,
			;        000h if not
	mov	a,c
	cpi	nmbdev
	jc	devok
	mvi	a,nmbdev; if dev # >= nmbdev,
			; set to nmbdev
devok:
	call	tbljmp	; jump to dev poll code

devtbl:
	dw	polco0	; poll console #0 output
	dw	polco1	; poll console #1 output
	dw	polco2	; poll console #2 output
	dw	polco3	; poll console #3 output
	dw	rtnempty;polco4	; poll console #4 output
	dw	rtnempty;polco5	; poll console #5 output
	dw	rtnempty;polco6	; poll console #6 output
	dw	rtnempty;polco7	; poll console #7 output
	dw	polci0	; poll console #0 input
	dw	polci1	; poll console #1 input
	dw	polci2	; poll console #2 input
	dw	polci3	; poll console #3 input
	dw	rtnempty;polci4	; poll console #4 input
	dw	rtnempty;polci5	; poll console #5 input
	dw	rtnempty;polci6	; poll console #6 input
	dw	rtnempty;polci7	; poll console #7 input
	dw	pollpt0	; poll printer #0 output
	dw	rtnempty;pollpt1	; poll printer #1 output
nmbdev	equ	($-devtbl)/2	; number of devices to poll
	dw	rtnempty; bad device handler
;


; Select / Protect Memory
;
selmemory:
			; Reg BC = adr of mem descriptor
			; BC ->  base   1 byte,
			;        size   1 byte,
			;        attrib 1 byte,
			;        bank   1 byte.
	cpi	020h
	jz	$
	lxi	h,3
	dad	b
	mov	a,m
	ani	7
	out 	0c0h

	ret
;
; Start Clock
;
startclock:
			; will cause flag #1 to be set
			;  at each system time unit tick
	mvi	a,0ffh
	sta	tickn
	ret
;
; Stop Clock
;
stopclock:
			; will stop flag #1 setting at
			;  system time unit tick
	xra	a
	sta	tickn
	ret
;
; Exit Region
;
exitregion:
			; EI if not preempted or in dispatcher
	lda	preemp
	ora	a
	rnz
	ei
	ret
;
; Maximum Console Number
;
maxconsole:
	mvi	a,nmbcns
	ret
;
; System Initialization
;
systeminit:
;
;  This is the place to insert code to initialize
;  the time of day clock, if it is desired on each
;  booting of the system.
;	C= BREAKPOINT RESTART NUMBER
;	DE= BREAKPOINT RESTART HANDLER ADDRESS
;	HL= DIRECT XIOS INTERCEPT JUMP TABLE ADDRESS

	mvi	a,0c3h
	sta	0038h
	lxi	h,inthnd
	shld	0039h		; JMP INTHND at 0038H

	mvi	a,0h	
	out	0E2h	; source bank 0
	out	0e5h	; source high 0
	out	0e7h	; dest high 0
	out	0e4h	; source low 0
	out	0e6h	; dest low 0
	out	0e9h	; count high 0
	mvi	a,40h	; move 40h bytes
	out	0e8h	; count low 0

	mvi	a,01h	
	out	0E3h	; destination bank
	; cmd=move s to d, but only to/from common, above boundary
	mvi	a,04h	
	out	0e0h	; single thread, no need to wait

	mvi	a,02h	
	out	0E3h	; destination bank
	mvi	a,04h	
	out	0e0h	; single thread, no need to wait

	mvi	a,03h	
	out	0E3h	; destination bank
	mvi	a,04h	
	out	0e0h	; single thread, no need to wait

	mvi	a,04h	
	out	0E3h	; destination bank
	mvi	a,04h	
	out	0e0h	; single thread, no need to wait

	mvi	a,05h	
	out	0E3h	; destination bank
	mvi	a,04h	
	out	0e0h	; single thread, no need to wait

	mvi	a,06h	
	out	0E3h	; destination bank
	mvi	a,04h	
	out	0e0h	; single thread, no need to wait

	mvi	a,07h	
	out	0E3h	; destination bank
	mvi	a,04h	
	out	0e0h	; single thread, no need to wait

	mvi	a,0h
	out	0bbh	;interval high
	mvi	a,50	;50 * 20 =1000
	out	0bah	;interval low
	mvi 	a,081h	; enable int timer 0
	out	0b8h		; init interrupt 

	db	0edh,056h	; Interrupt Mode 1
				; ** Z80 Instruction **
;	ei

	ret			;   & return

;
; Idle procedure
;
;idle:
;	ret

;	-or-

;	ei
;	hlt
;	ret			; for full interrupt system

;
;  MP/M II V2.0   Interrupt Handlers
;

flagwait equ	132
flagset	equ	133
dsptch	equ	142

inthnd:
			; Interrupt handler entry point
			;  All interrupts gen a RST 7
			;  Location 0038H contains a jmp
			;  to INTHND.
	shld	svdhl
	pop	h
	shld	svdret
	push	psw
	lxi	h,0
	dad	sp
	shld	svdsp		; save users stk ptr
	lxi	sp,lstintstk	; lcl stk for intr hndl
	push	d
	push	b

	mvi	a,0ffh
	sta	preemp	; set preempted flag

	in	0b8h		; read timer 0  
	ani	010000000b	; test & jump if clk int
	jnz	clktick
;	.....
	jmp	intdone


clktick:
				; timer tick interrupt
	lda	tickn
	ora	a		; test tickn, indicates
				;  delayed process(es)
	jz	notickn
	mvi	c,flagset
	mvi	e,1
	call	xdos		; set flag #1 each tick
notickn:
	lxi	h,tickcnt
	dcr	m		; dec tick cntr
	jnz	not1sec
	mvi	m,20
	mvi	c,flagset
	mvi	e,2
	call	xdos		; set flag #2 @ 1 sec
not1sec:
;	jmp	intdone
;
;	...
; Other interrupt handlers
;	...
;
intdone:
	xra	a
	sta	preemp	; clear preempted flag
	pop	b
	pop	d
	lhld	svdsp
	sphl			; restore stk ptr
	pop	psw
	lhld	svdret
	push	h
	lhld	svdhl
; The following dispatch call will force round robin
;  scheduling of processes executing at the same priority
;  each 1/50th of a second.
; Note: Interrupts are not enabled until the dispatcher
;  resumes the next process.  This prevents interrupt
;  over-run of the stacks when stuck or high frequency
;  interrupts are encountered.
	jmp	pdisp		; MP/M dispatch
;
;
;
; BIOS Data Segment
;
tickcnt:	db	20	; 20 tick cntr = 1 sec
intstk:			; local intrpt stk
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h
	dw	0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h
lstintstk:
svdhl:	dw	0	; saved Regs HL during int hndl
svdsp:	dw	0	; saved SP during int hndl
svdret:	dw	0	; saved return during int hndl
tickn:	db	0	; ticking boolean,true = delayed
	if	debug
intmsk:	db	44h	; intrpt msk, enables clk intrpt, & con2
	else
intmsk:	db	54h	; intrpt msk, enables clk intrpt, & con0/2
	endif
preemp:	db	0	; preempted boolean
;

	db	0	;force out last byte in hex file

	end
