*
* Assembly language macros
* Written by Talin
*

MACROS_I		set		1

		include 'exec/types.i'

AbsExecBase		equ		4
_AbsExecBase	equ		4

VALIDNARG	macro	; VALIDNARG	min,narg,max
					; if #paramters not in range, FAIL occurs

		if narg-3
			fail
		endc

		iflt	\2-\1
			fail
		endc

		ifgt	\2-\3
			fail
		endc

			endm

*	Call FuncName[,LibAddr[,SAVE]]

Call		MACRO
			ifge	narg-3
			move.l	a6,-(sp)
			endc

			ifge	narg-2
			movea.l	\2,a6
			endc

			xref	_LVO\1
			jsr		_LVO\1(a6)

			ifge	narg-3
			move.l	(sp)+,a6
			endc

			ENDM

*	JumpLib	FuncName,LibAddr

JumpLib		MACRO
			movea.l	_\2,a6
			xref	_LVO\1
			jmp		_LVO\1(a6)
			ENDM

Jump		MACRO
			xref	_LVO\1
			jmp		_LVO\1(a6)
			ENDM

*	Call_Lib	FuncName,LibAddr


Call_Lib	MACRO
			movea.l	_\2,a6
			xref	_LVO\1
			jsr		_LVO\1(a6)
			ENDM

*	CallEx FuncName

CallEx		MACRO
			movea.l	AbsExecBase,a6
			xref	_LVO\1
			jsr		_LVO\1(a6)
			ENDM

*	CallInt	Funcname

CallInt		MACRO
			movea.l	_IntuitionBase,a6		
			xref	_LVO\1
			jsr		_LVO\1(a6)
			ENDM

*	CallGfx	Funcname

CallGfx		MACRO
			movea.l	_GfxBase,a6
			xref	_LVO\1
			jsr		_LVO\1(a6)
			ENDM

*	CallDos	Funcname

CallDos		MACRO
			movea.l	_DOSBase,a6
			xref	_LVO\1
			jsr		_LVO\1(a6)
			ENDM

* Call with parameters
* 	CallP	Funcname,Library,(s1,d1),(s2,d2),(s3,d3)...

CallP		MACRO

			ifge	narg-3
			move.l	\3
			endc

			ifge	narg-4
			move.l	\4
			endc

			ifge	narg-5
			move.l	\5
			endc

			ifge	narg-6
			move.l	\6
			endc

			ifge	narg-7
			move.l	\7
			endc

			ifge	narg-8
			move.l	\8
			endc

			movea.l	_\2,a6
			xref	_LVO\1
			jsr		_LVO\1(a6)
			ENDM

;			Save	reg,reg,reg		- push up to 3 regs on stack

Save		macro
			ifge	narg-1
			move.l	\1,-(sp)
			endc
			ifge	narg-2
			move.l	\2,-(sp)
			endc
			ifge	narg-3
			move.l	\3,-(sp)
			endc
			endm

;			Restore	reg,reg,reg		- pop up to three registers off stack
;			note - regs must be in same order as for save.

Restore		macro
			ifge	narg-3
			move.l	(sp)+,\3
			endc
			ifge	narg-2
			move.l	(sp)+,\2
			endc
			ifge	narg-1
			move.l	(sp)+,\1
			endc
			endm

SaveM		macro
			movem.l	\1,-(sp)
			endm

RestoreM	macro
			movem.l	(sp)+,\1
			endm

Push		macro
			ifge	narg-1
			move.\0	\1,-(sp)
			endc
			ifge	narg-2
			move.\0	\2,-(sp)
			endc
			ifge	narg-3
			move.\0	\3,-(sp)
			endc
			ifge	narg-4
			move.\0	\4,-(sp)
			endc
			ifge	narg-5
			move.\0	\5,-(sp)
			endc
			endm

BEGIN_IO	macro
			move.l		IO_DEVICE(\1),a6
			jsr			-30(a6)
			endm

CLRU		macro
			swap		\1
			clr.w		\1
			swap		\1
			endm

TOUPPER		macro		
			cmp.b		#$E0,\1				; if register in in foreign set
			blo.s		\@TOUP1				; then
			sub.b		#32,\1				; make upper case foreign
			bra.s		\@TOUP3
\@TOUP1		cmp.b		#$61,\1				; lower case 'a'
			blo.s		\@TOUP3
			cmp.b		#$7a,\1				; lower case 'z'
			bhi.s		\@TOUP3
			sub.b		#32,\1
\@TOUP3
			endm

; IMATCH - a macro that quickly does a case-insensitive character test
;	Note this function destroys the two registers passed to it.
;	Usage:
;			IMATCH		reg1,reg1,matchlabel,nomatchmabel

IMATCH		macro

			cmp.b		\1,\2					; if characters match
			beq.s		\3
			eor.b		\1,\2					; get exclusive or of characters
			cmp.b		#32,\2					; if different only by bit 32
			bne.s		\4						; then
			bset		#5,\1					; force to upper case
			cmp.b		#$61,\1					; if less than lower case 'a'
			blo.s		\4						; then no match
			cmp.b		#$7a,\1					; if less that or equal to lower 'z'
			bls.s		\3						; then match
			cmp.b		#$E0,\1					; if less than lower case 'à'
			blo.s		\4						; then no match
			bra.s		\3						; then match

			endm

* enum		initval,arg1,arg2,arg3,arg4...

enum		MACRO			; set all values to increasing order

			ifge	narg-2
\2			equ		\1+0
			endc

			ifge	narg-3
\3			equ		\1+1
			endc

			ifge	narg-4
\4			equ		\1+2
			endc

			ifge	narg-5
\5			equ		\1+3
			endc

			ifge	narg-6
\6			equ		\1+4
			endc

			ifge	narg-7
\7			equ		\1+5
			endc

			ifge	narg-8
\8			equ		\1+6
			endc

			ifge	narg-9
\9			equ		\1+7
			endc

			ENDM

;EVEN		MACRO
;			cnop	0,2				; force location counter to even boundary
;			ENDM

* supplemetal macros for exec/types.i

evener		equ		$fffffffe			; force data item to even boundary

ptr			MACRO
\1			equ		(SOFFSET+1)&evener
SOFFSET		set		\1+4
			ENDM

word16		MACRO
\1			equ		(SOFFSET+1)&evener
SOFFSET		set		\1+2
			ENDM

block		MACRO
\1			equ		SOFFSET
SOFFSET		set		SOFFSET+\2
			ENDM

*
* More Assembly language macros
* Written by JPearce
*

DECLARE		macro
			xdef		_\1
_\1
			ENDM

TOLOWER		macro		
			cmp.b		#$c0,\1				; if register in in foreign set
			blo.s		\@TOLO1				; then
			cmp.b		#$de,\1				; is it already lower case?
			bhi.s		\@TOLO3				; note... don't do German "ss"
			add.b		#32,\1				; make lower case foreign
			bra.s		\@TOLO3
\@TOLO1		cmp.b		#$41,\1				; upper case 'a'
			blo.s		\@TOLO3
			cmp.b		#$5a,\1				; upper case 'z'
			bhi.s		\@TOLO3
			add.b		#32,\1
\@TOLO3
			endm

MAX			macro		; MAX.e ds,dd <,U>
						; where e = size, ds = source, dd = dest, U = unsigned

			VALIDNARG	2,narg,3

			cmp.\0		\1,\2		; test if dd > de

		if narg-3
			bhi.s		\@MAX1		; yes, dd has right value (unsigned)
		else
			bgt.s		\@MAX1		; (signed)
		endc
			move.\0		\1,\2		; move ds into dd
\@MAX1
			endm

MIN			macro		; MIN.e ds,dd <,U>
						; where e = size, ds = source, dd = dest, U = unsigned

			VALIDNARG	2,narg,3

			cmp.\0		\1,\2		; test if dd > de

		if narg-3
			blo.s		\@MIN1		; yes, dd has right value (unsigned)
		else
			blt.s		\@MIN1		; (signed)
		endc
			move.\0		\1,\2		; move ds into dd
\@MIN1
			endm

ABS			macro		; ABS dn
			tst.\0		\1			; test it
			bpl.s		\@ABS1		; if positive, skip
			neg.\0		\1			; negate it
\@ABS1
			endm

CLAMP		macro		; CLAMP.e	dl,dv,dh <,U> (result in dv)

			VALIDNARG	3,narg,4

		if narg-4
			MAX.\0		\1,\2,U
			MIN.\0		\3,\2,U
		else
			MAX.\0		\1,\2
			MIN.\0		\3,\2
		endc			
			endm

NEW			macro		; NEW	rn,size <,t>
						; where rn is a register (can't be d0)
						; and t is CHIP,CLEAR or PUBLIC

			VALIDNARG	2,narg,3

			subq.w		#4,sp
			movem.l		a0/a1/a6/d0/d1,-(sp)
			move.l		AbsExecBase,a6

	if narg-2
		if '\3'=='CHIP'
			moveq		#2,d1
		endc
		if '\3'=='PUBLIC'
			moveq		#1,d1
		endc
		if '\3'=='CLEAR'
			move.l		#1<<16,d1
		endc
		if '\3'=='CHIP_PUBLIC'
			moveq		#3,d1
		endc
		if '\3'=='CHIP_CLEAR'
			move.l		#2+(1<<16),d1
		endc
		if '\3'=='PUBLIC_CLEAR'
			move.l		#1+(1<<16),d1
		endc
		if '\3'=='CHIP_PUBLIC_CLEAR'
			move.l		#3+(1<<16),d1
		endc
	else
			moveq		#0,d1
	endc

			move.l		#\2,d0
			Call		AllocMem
			move.l		d0,20(sp)
			movem.l		(sp)+,a0/a1/a6/d0/d1
			move.l		(sp)+,d0
			move.l		d0,\1
			endm

DELETE		macro		; DELETE rn,size  (rn cannot be d0/a1/a6)

		if narg-2
			fail
		endc

			xref		_LVOFreeMem
			movem.l		a0/a1/a6/d0/d1,-(sp)
			move.l		\1,d0
			beq.s		\@DEL1
			move.l		AbsExecBase,a6
			move.l		d0,a1
			move.l		#\2,d0
			jsr			_LVOFreeMem(a6)
\@DEL1		movem.l		(sp)+,a0/a1/a6/d0/d1

			endm

* end macro definitions
