;----------------------------------------------------------------------------
;File name:	URAn_XB.S			Revision date:	1996.03.04
;Creator:	Ulf Ronald Andersson		Creation date:	1991.05.07
;(c)1992 by:	Ulf Ronald Andersson		All rights reserved
;Released as:	FREEWARE		(NB: commercial sales forbidden!)
;File purpose:	Macro library for XBRA operations
;----------------------------------------------------------------------------
;	Condition ensures inclusion once per pass only
;
	ifnd	URAn_XB_defined
URAn_XB_defined	set	1
;
;----------------------------------------------------------------------------
;	Library macros:
;
;   The first 4 alter no registers
; XB_define	xbstruct,xbra_id	Defines header for routine code
; XB_gonext	xbstruct		Smart Link to next routine in chain
; XB_gonext_d	xbstruct		FAST Link to next routine in chain
; XB_donext_d	xbstruct		FAST Call to next routine in chain
;
;   The next 2 alter only register a0
; XB_gonext_a0	xbstruct		BEST Link to next routine in chain
; XB_donext_a0	xbstruct		BEST Call to next routine in chain
;
;   The next 2 alter only the choosen "areg"
; Pass_Frame	areg			areg->exception argument
; XB_donext	xbstruct,areg		Smart Call to next routine in chain
;
;   The next 3 affect d0-d2/a0-a2, since they use XBIOS Supexec
; XB_check	xbstruct,root		d0= found/last vector  flagged PL/MI
; XB_install	xbstruct,root		" + Installs xbstruct in chain(root)
; XB_remove	xbstruct,root		" + Removes xbstruct from chain(root)
;
; Legal forms for xbstruct & root here are mostly the same as for LEA & PEA,
;   except that for XB_define "xbstruct" is a free name for the new structure.
; "xbstruct" always refers to the first byte of the entire structure.
; "xbra_id" is a 4-character (longword) string
; "areg" is a free address register of your choice.
; XB_gonext_d & XB_donext_d are faster versions of XB_gonext & XB_donext,
;   but can only handle address modes where "xbstruct" begins with identifier.
;   eg: "XB_donext_d  my_ikbd_sub(pc)"  but  "XB_donext  (a5)+")
; XB_gonext_a0 & XB_donext_a0 are even faster, but destroy value in a0.
; Pass_Frame makes exception routines (eg: gemdos etc.) 68030-compatible,
;   by setting "areg" = stack pointer before exception (SSP or USP)
;
;XB_define may (optionally) have a third argument which, if present, will be
;placed in the link pointer as its initial value.
;
;----------------------------------------------------------------------------
;
	include	tos\URAn_DOS.S
;
;----------------------------------------------------------------------------
;
		RSRESET
xb_magic:	rs.l	1
xb_id:		rs.l	1
xb_next:	rs.l	1
xb_code:	rs.w	0
xb_size:	rs.w	0
;
;----------------------------------------------------------------------------
;	Macro definitions (with support variables)
;
;
Pass_Frame	macro	areg
	btst	#5,(sp)
	beq.s	.user\@
.super\@:
	tst	(_longframe).w
	bne.s	.new_cpu\@
.old_cpu\@:
	lea	6(sp),\1
	bra.s	.have_arg\@
.new_cpu\@:
	lea	8(sp),\1
	bra.s	.have_arg\@
.user\@:
	move.l	USP,\1
.have_arg\@:
	endm
;
;----------------------------------------------------------------------------
;
XB_define	macro	xbstructname,xbra_id,init_link
\1:	dc.l	'XBRA',\2
	ifc	'','\3'
	dc.l	0
	elseif
	dc.l	\3
	endc
	endm
;
;----------------------------------------------------------------------------
;
XB_donext_a0	macro	xbstruct
	move.l	8+\1,a0
	jsr	(a0)
	endm
;
;
XB_donext_d	macro	xbstruct
	pea	.l\@(pc)
	move.l	8+\1,-(sp)
	rts
.l\@:
	endm
;
;
XB_donext	macro	xbstruct,areg
	lea	\1,\2
	move.l	8(\2),\2
	jsr	(\2)
	endm
;
;----------------------------------------------------------------------------
;
XB_gonext_a0	macro	xbstruct
	move.l	8+\1,a0
	jmp	(a0)
	endm
;
;
XB_gonext_d	macro	xbstruct
	move.l	8+\1,-(sp)
	rts
	endm
;
;
XB_gonext	macro	xbstruct
	movem.l	a0-a1,-(sp)
	lea	\1,a0
	move.l	8(a0),4(sp)
	move.l	(sp)+,a0
	rts
	endm
;
;----------------------------------------------------------------------------
;
XB_check_defined	set	0
;
XB_check	macro	xbstruct,root
;
	ifne	XB_check_defined=0
	bra.s	XB_check_code_end
;
XB_check_code:
	movem.l	a3/a4,-(sp)
	movem.l	12(sp),a3/a4	;a3 -> struct  a4 -> chain root
	subq	#4,sp		;reserve result storage on stack
;
	gemdos	Super,1.w	;User or Super mode call ?
	tst.l	d0
	bmi.s	.done_super_1
	gemdos	Super,!
.done_super_1:			;here CPU is in supervisor state
	move.l	d0,-(sp)	;push -1 or previous SSP
	move	SR,d2		;d2 = entry interrupt mask
	or	#$0700,SR	;disable interrupts
;
.search_lp:
	move.l	a4,d0
	bset	#31,d0			;flag vector missing as MI
	move.l	(a4),d1
	beq.s	.done_search		;exit if vector missing
	move.l	d1,a4
	subq	#xb_code-xb_next,a4
	cmpi.l	#'XBRA',xb_magic-xb_next(a4)
	bne.s	.done_search		;exit if chain broken
	move.l	xb_id-xb_next(a4),d1	;d1 = current id
	cmp.l	xb_id(a3),d1		;d1 == sought id ?
	bne.s	.search_lp		;loop back to check remaining chain
	bclr	#31,d0		;flag vector found as PL
.done_search:
	move.l	d0,4(sp)	;store search result in stack
;
	move	d2,SR		;restore entry interrupt mask
	move.l	(sp)+,d0
	bmi.s	.done_super_2
	gemdos	Super|_ind,d0
.done_super_2:			;here CPU is back in entry state
;
	move.l	(sp)+,d0	;d0 = search result from stack
	movem.l	(sp)+,a3/a4
	rts	;d0=found_vector  or  (last_chain_vector+1<<31)
XB_check_code_end:
	endc
;
	pea	\2
	pea	\1
	bsr	XB_check_code
	addq	#8,sp
;
XB_check_defined	set	XB_check_defined+1
	endm	;d0=found_vector/(last_chain_vector+1<<31) flagged PL/MI
;
;----------------------------------------------------------------------------
;
XB_install_defined	set	0
;
XB_install	macro	xbstruct,root
	ifne	XB_install_defined=0
	bra.s	XB_install_code_end
;
XB_install_code:
	movem.l	a3/a4,-(sp)
	movem.l	12(sp),a3/a4	;a3 -> struct  a4 -> chain root
	subq	#4,sp		;reserve result storage on stack
;
	gemdos	Super,1.w	;User or Super mode call ?
	tst.l	d0
	bmi.s	.done_super_1
	gemdos	Super,!
.done_super_1:			;here CPU is in supervisor state
	move.l	d0,-(sp)	;push -1 or previous SSP
	move	SR,d2		;d2 = entry interrupt mask
	or	#$0700,SR	;disable interrupts
;
	move.l	a3,a1
	move.l	a4,a2
;
.search_lp:
	move.l	a4,d0
	bset	#31,d0			;flag vector missing as MI
	move.l	(a4),d1
	beq.s	.done_search		;exit if vector missing
	move.l	d1,a4
	subq	#xb_code-xb_next,a4
	cmpi.l	#'XBRA',xb_magic-xb_next(a4)
	bne.s	.done_search		;exit if chain broken
	move.l	xb_id-xb_next(a4),d1	;d1 = current id
	cmp.l	xb_id(a3),d1		;d1 == sought id ?
	bne.s	.search_lp		;loop back to check remaining chain
	bclr	#31,d0		;flag vector found as PL
.done_search:
	move.l	d0,4(sp)	;store search result in stack
;
	bpl.s	.done_install
	lea	xb_next(a1),a1
	move.l	(a2),(a1)+	;link new XBRA to old chain
	move.l	a1,(a2)		;store -> new XBRA as chain root
.done_install:
;
	move	d2,SR		;restore entry interrupt mask
	move.l	(sp)+,d0
	bmi.s	.done_super_2
	gemdos	Super|_ind,d0
.done_super_2:			;here CPU is back in entry state
;
	move.l	(sp)+,d0	;d0 = search result from stack
	movem.l	(sp)+,a3/a4
	rts	;d0=found_vector  or  (last_chain_vector+1<<31)
XB_install_code_end:
	endc
;
	pea	\2
	pea	\1
	bsr	XB_install_code
	addq	#8,sp
;
XB_install_defined	set	XB_install_defined+1
	endm
;
;----------------------------------------------------------------------------
;
XB_remove_defined	set	0
;
XB_remove	macro	xbstruct,root
	ifne	XB_remove_defined=0
	bra.s	XB_remove_code_end
;
XB_remove_code:
	movem.l	a3/a4,-(sp)
	movem.l	12(sp),a3/a4	;a3 -> struct  a4 -> chain root
	subq	#4,sp		;reserve result storage on stack
;
	gemdos	Super,1.w	;User or Super mode call ?
	tst.l	d0
	bmi.s	.done_super_1
	gemdos	Super,!
.done_super_1:			;here CPU is in supervisor state
	move.l	d0,-(sp)	;push -1 or previous SSP
	move	SR,d2		;d2 = entry interrupt mask
	or	#$0700,SR	;disable interrupts
;
	move.l	a3,a1
	move.l	a4,a2
;
.search_lp:
	move.l	a4,d0
	bset	#31,d0			;flag vector missing as MI
	move.l	(a4),d1
	beq.s	.done_search		;exit if vector missing
	move.l	d1,a4
	subq	#xb_code-xb_next,a4
	cmpi.l	#'XBRA',xb_magic-xb_next(a4)
	bne.s	.done_search		;exit if chain broken
	move.l	xb_id-xb_next(a4),d1	;d1 = current id
	cmp.l	xb_id(a3),d1		;d1 == sought id ?
	bne.s	.search_lp		;loop back to check remaining chain
	bclr	#31,d0		;flag vector found as PL
.done_search:
	move.l	d0,4(sp)	;store search result in stack
;
	bmi.s	.done_remove
	move.l	d0,a0				;a0 -> link -> found XBRA
	move.l	(a0),a1				;a1 -> xb_code of found XBRA
	move.l	xb_next-xb_code(a1),(a0)	;unlink found XBRA from chain
.done_remove:
;
	move	d2,SR		;restore entry interrupt mask
	move.l	(sp)+,d0
	bmi.s	.done_super_2
	gemdos	Super|_ind,d0
.done_super_2:			;here CPU is back in entry state
;
	move.l	(sp)+,d0	;d0 = search result from stack
	movem.l	(sp)+,a3/a4
	rts	;d0=found_vector  or  (last_chain_vector+1<<31)
;
XB_remove_code_end:
	endc
;
	pea	\2
	pea	\1
	bsr	XB_remove_code
	addq	#8,sp
;
XB_remove_defined	set	XB_remove_defined+1
	endm
;
;----------------------------------------------------------------------------
	endc	;URAn_XB_defined
;----------------------------------------------------------------------------
; End of file:	URAn_XB.S
;----------------------------------------------------------------------------
