;************************************************
;*						*
;*	P-CP/M Basic Disk Operating System 	*
;*		Exception Handling Module	*
;*						*
;*	Version 0.0 -- July    21, 1982		*
;*	Version 0.1 -- July    25, 1982		*
;*	Version 0.2 -- 821014 (Zilog)		*
;*	Version 0.3 -- 821222 (Zilog)		*
;*						*
;************************************************


__text:	.sect

;****************************************************
;*
;* Externals
;*
;****************************************************

	.global	_sysseg
	.global _tpa_lp
	.global _tpa_hp


;****************************************************
;*
;* Globals and Constants
;*
;****************************************************

	.global	_initexc

BGETSEG .equ 18		;Bios call to get mem seg tbl
BSETEXC	.equ 22		;Bios call to set xvec

BIOS_SC	.equ 3		;Bios system call

;****************************************************
;*
;* initexc(vecarray) -- initialize exception vector
;*
;*	The BDOS maintains its OWN exception vector.
;*	This routine sets up the BIOS exception
;*	vectors to point to handlers in this module,
;*	that vector again using the BDOS vectors.
;*
;*	Only vectors  2-23 and 36-38 are handled by
;*	the BDOS, leaving 0-1 and 24-35 for the BIOS
;*
;****************************************************

_initexc:
				;* sp -> return addr
				;*    +2 table addr

	ld	r3,#BSETEXC	; r3 =  BDOS command
	ldl	rr4,#2		;rr4 =  exception #
	ld	r6,_sysseg	;rr6 -> handler
	lda	r7,exchndl	;	(segmented)

	dec	r15,#10		;space to save regs
				; on stack over SC
initloop:
	ldm	@r15,r3,#5
	sc	#BIOS_SC
	ldm	r3,@r15,#5
	inc	r5,#1		;step exception #
	inc	r7,#2		;and handler addr.
	cp	r5,#24		;done 23 yet?
	jr ne	init1		; no
	ld	r5,#36		; yes--skip to 36
	inc	r7,#8		;  we have entries in
				;  table for 32-36
				;  but system uses 
				;  them.  Skip.
init1:	cp	r5,#48		;done all 48?
	jr ne	initloop	; no--loop

	inc	r15,#10		;clean stack

	ld	r2,2(r15)	;save vector address
	ld	evec_adr,r2

	ld	r0,#18		; 18 long entries
	subl	rr4,rr4
init2:				;clear vector array

; should check current entry, and keep it if
; between old TPA and current TPA limits.

; The TPA limits are flaky because we have two TPA's,
; for split and merged spaces, not to mention
; segmented programs.

; What we are going to do is clear the lot.
; Programs that want permanent traps can use the
; Bios to set the trap vector.

	ldl	rr6,@r2		; rr6 = exception addr

	ldl	@r2,rr4
init3:
	inc	r2,#4
	djnz	r0,init2

	ret			;return

;****************************************************
;*
;* Exception Handler Routine
;*
;*	An exception handler is called as a subroutine
;*	in segmented mode, with all registers saved
;*	on the stack.
;*
;*	Returning (ret) from the handler (in segmented
;*	mode) will return to the state-restorer.
;*
;****************************************************

exchndl:
	calr	except
excrtn0:
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except
	calr	except


except:			; general exception handler

	ldctl	r0,FCW		; NONSEGMENTED
	res	r0,#15
	ldctl	FCW,r0

	popl	rr0,@r15	; get return address 
				;   from above array
	sub	r1,#excrtn0	; r1 now = 4*encoded 
	srl	r2,#2		;   exception number

; r1/4 = [0..21, 22..37] represents exceptions
;        [2..23, 32..47].
;
; If r1/4 is in the range [0..9, 22..29] then the
; exception may be redirected by the BDOS.

	cp	r1,#36
	jr le	chkredir
	cp	r1,#88
	jr lt	dfltexc
	cp	r1,#116
	jr gt	dfltexc
				; in range of redirected exceptions
	sub	r1,#48		; subtract 4*12 to normalize [0..9,22..29]
				;			into [0..9,10..17]
chkredir:
	ld	r2,evec_adr	; index into exception
				;  vector array
	ldl	rr4,r2(r1)	; rr4 -> handler
	testl	rr4		; if non-zero
	jr nz	usrexc		;   go do it

				;not redirected, 
				; do default handler
	cp	r1,#40
	jr lt	dfltexc
	add	r1,#48		; add 4*12 sub'd above
dfltexc:
	srl	r1,#2		; divide r1 by 4
				; r1 =    [0..21,22..37]
				; meaning [2..23,32..47]
	add	r1,#2		;get back real except#
	cp	r1,#23
	jr le	lowexc
	add	r2,#12
lowexc:	
	push	@r15,r1		; save exception #
				; print default msg
	clr	r6
	ld	r7,#excmsg1
	calr	print
	calr	prtdollar
	pop	r1,@r15
	calr	prtbyte
	clr	r6
	ld	r7,#excmsg2
	calr	print
	calr	prtdollar
	popl	rr0,@r15
	calr	prtlong
	clr	r6
	ld	r7,#excmsg3
	calr	print

	clr	r5		; warm boot
	sc	#2
	ret

usrexc:			; call user exception handler
			;	rr4 -> handler

; user exception handler called in with FCW restored
; to that at the time of the exception, with the
; stack containing a copy of the context block.
; On top of the context block will be a GARBAGE
; return address of the appropriate mode.

; Handler must exit with XFER system call.

; stack now contains:
;	return address (long) to trap_ret
;	normal r0..r15
;	reason, fcw, PC (long)

	ld	r1,38(r15)	;34+4 r1 = user FCW
	bit	r1,#14		;system mode?
	jr nz	sysexc		; yes
				; no
	ldl	rr2,32(r15)	;28+4 rr2 = user stack
	bit	r1,#15		;segmented?
	jr nz	segusrx		; yes
				; no -- get seg
	ld	r2,42(r15)	;38+4
segusrx:
	ldctl	r0,FCW		;go segmented
	set	r0,#15
	ldctl	FCW,r0

	sub	r3,#44		;copy frame to usr
				; (with junk PC)
	ld	r0,#22
	ldir	@r2,@r14,r0

	pushl	@r14,rr4	;go
	pushl	@r14,rr0
	iret

sysexc:				;system mode exc.
	set	r1,#15		; go segmented
	ldctl	FCW,r1
	jp	@r4		;go
	


;****************************************************
;*
;*  Subroutines
;*
;****************************************************

print:
	ld	r5,#9		;PRINTMSG
	sc	#2		;BDOS
	ret

prtdollar:
	ld	r5,#2		;PRINTCHAR
	ldl	rr6,#24h	; dollarsign
	sc	#2
	ret

prtlong:		; print rr0 as hex long
	push	@r15,r1
	ex	r0,r1
	calr	prtword
	pop	r1,@r15

prtword:		; print r1 as hex word
	push	@r15,r1
	ldb	rl1,rh1
	calr	prtbyte
	pop	r1,@r15

prtbyte: 		; Print rl1 as hex byte
	push	@r15,r1
	srl	r1,#4
	calr	prtnib
	pop	r1,@r15

prtnib:
	and	r1,#15
	cp	r1,#10
	jr lt	lt10
	add	r1,#7
lt10:
	add	r1,#30h
	ld	r7,r1
	ld	r5,#2		;PRINTBYTE
	sc	#2		;BDOS
	ret

;****************************************************
;*
;* data
;*
;****************************************************

__data:	.sect

excmsg1:
	.byte	13,10,10,"Exception $"

excmsg2:
	.byte	" at user address $"

excmsg3:
	.byte	".  Aborted.$"


;****************************************************
;*
;* bss
;*
;****************************************************

__bss:	.sect

evec_adr:
	.block	2

	.end
