;
;  PARALLEL LIBRARY ROUTINES - PLIBMAC.MAR
;
;  This file contains all of the macro routines required for the Parallel
;  Library.
;
;
;*******************************************************************************
;*******************************************************************************
;
;               Parallel Library Routines - Version 2.0
;
;               COPYRIGHT 1985, 1986 DIGITAL EQUIPMENT CORPORATION
;
;*******************************************************************************
;*******************************************************************************


;
	.title	parallel_library_macro_routines

;
;  interlocked bit setting routine.
;
;  This routine sets the low-order bit in the longword interlocked and counts
;  the number of iterations required.
;
;  Parameters:
;
;	first - longword whose low-order bit is the flag to be set interlocked.
;
;	second - total count of the number of iterations required to fetch the
;		 interlock.  Note, this parameter is not zeroed at the start
;		 of the routine so the count can continue from the last call.
;
;	third - number of times that this routine has been called.  This is
;		incremented only once upon routine entry.
;
;  Return value:
;
;	1 = success  (routine does not return until it sucessfully sets the bit)
;
;
	.entry	plib$set_bit_interlocked, ^M<>

	cmpl	(ap),#1			; test if only 1 argument
	bneq	count_start		; and if not 1, branch to counter code.

;
;  This code handles the case of only one argument - namely the longword
;  that contains the bit to be set.
;

main_loop:
	bbssi	#0,@4(ap),inside_loop	; attempt to set the bit

	movl	#1,r0			; set status of success
	ret				;   ...and return

inside_loop:
	tstl	@4(ap)			; test bit to see if clear yet
	bneq	inside_loop		; if bit still set, keep waiting
	brb	main_loop		; Aha!  Bit clear - jump back and try
					; this interlocked.

;
;  This code handles the case where there are more than 1 argument and so
;  this is the counter form.
;

count_start:
	incl	@12(ap)			; increment the "entry" count just once

c_main_loop:
	incl	@8(ap)			; increment loop counter for timing

	bbssi	#0,@4(ap),c_inside_loop	; do the interlocked bit set.  On
					; failure, go to the more efficient
					; (non-interlocked) spin loop. (As
					; per suggestion from John Sopka.)

	movl	#1,r0			; set status of success
	ret				;   ...and return

c_inside_loop:
	incl	@8(ap)			; increment counter again.
	tstl	@4(ap)			; test bit to see if clear yet
	bneq	c_inside_loop		; if bit still set, keep waiting
	brb	c_main_loop		; Aha!  Bit clear - jump back and try
					; this interlocked.
	


;*******************************************************************************
;
;  interlocked bit clearing routine.
;
;  This routine clears the low-order bit in the longword interlocked and counts
;  the number of iterations required.
;
;  Parameters:
;
;	first - longword whose low-order bit is the flag to be cleared
;		interlocked.
;
;	second - total count of the number of iterations required to clear the
;		 bit.  Note, this parameter is not zeroed at the start of the
;		 routine so the count can continue from the last call.
;
;  Return value:
;
;	1 = success
;
;	0 = Error!  Bit designated for clearing was already clear.  (This is
;		an error since no process should call this routine unless it
;		"owns" the lock.)
;
;
	.entry	plib$clear_bit_interlocked, ^M<>

	cmpl	(ap),#1			; test if only 1 argument
	beql	clear_start		; branch if only 1

	incl	@8(ap)			; increment loop counter for timing

clear_start:
	bbcci	#0,@4(ap),lock_error	; do the interlocked bit clear.  On
					; error, jump to error handling code.

	movl	#1,r0			; set status of success
	ret				;   ...and return

lock_error:
	movl	#0,r0			; lock error discovered.  Bit was
	ret				; already clear...  Set status to
					; failure and return



;*******************************************************************************
;
;  Add word interlocked routine
;
;  This routine provides an interface to the VAX ADAWI instruction to perform
;  interlocked word additions.
;
;  Format
;
;	ret_status = plib$add_word_interlocked (add, sum)
;
;  Arguments
;
;	add - Value to add to the SUM argument.  Word value that is passed by
;		reference and must be word aligned.
;
;	sum - Location to add the contents of the ADD argument to.  Word value
;		passed by reference, must be word aligned and is modified.
;
;  Return status
;
;	The possible return values are:
;
;		0 - The value of SUM after the addition was zero.
;
;		1 - The value of SUM after the addition was non-zero.
;

	.entry	plib$add_word_interlocked, ^M<>

	adawi	@4(ap), @8(ap)		; perform the adawi instruction
	bneq	not_zero		; check if the result was zero
	movl	#0,r0			; if zero, return a zero
	ret

not_zero:				; resultant value was non-zero so
	movl	#1,r0			; return the status of "non-zero"
	ret

;
;******************************************************************************
;
;  This routine returns the PC of the routine that just called us.  This is
;  to assist with the PLIB$SHARE_CODE routine as an easy way of getting a
;  starting virtual address for the region of code to be shared.
;
;  Arguments
;
;	- none -
;
;  Return value
;
;	The value returned is the PC from the last call frame on the stack.
;
;  Restrictions
;
;  Comments
;

	.entry	plib$current_pc, ^M<>
;
	movl	16(fp), r0
	ret
	.end
