/*
 * axp_incstat.s
 *
 * Atomic math operations
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1996,1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <machine/asm.h>
#include <machine/regdef.h>

/*
 * Atomically increment a 64-bit word.
 * Load it locked, increment it, store it.
 * The logical thing might seem to be load,
 * align, inc, store, beq to beginning to try again.
 * The Alpha AXP arch ref man suggests not
 * doing this because the processor predicts
 * backward branch taken, so instead we do a bne
 * forward-then-backward (we optimistically assume
 * that conflict is unlikely, which seems right).
 *
 * This happens to return the old value in case
 * anyone cares.
 */
LEAF(nasd_atomic_inc64)
1:
	ldq_l	v0,(a0)
	bis	zero,zero,zero /* magic to align subsequent instructions */
	addq	v0,1,t0
	stq_c	t0,(a0)
	beq	t0,2f
	ret	zero,(ra)
2:
	br	zero,1b
END(nasd_atomic_inc64)

/*
 * Same as atomic_inc64, except instead of adding 1, we
 * add the contents of a1 (next argument).
 */
LEAF(nasd_atomic_add64)
1:
	ldq_l	v0,(a0)
	bis	zero,zero,zero /* magic to align subsequent instructions */
	addq	v0,a1,t0
	stq_c	t0,(a0)
	beq	t0,2f
	ret	zero,(ra)
2:
	br	zero,1b
END(nasd_atomic_add64)

/*
 * Same as atomic_add64, except we subtract a1 (next argument)
 * instead of adding it.
 */
LEAF(nasd_atomic_sub64)
1:
	ldq_l	v0,(a0)
	bis	zero,zero,zero /* magic to align subsequent instructions */
	subq	v0,a1,t0
	stq_c	t0,(a0)
	beq	t0,2f
	ret	zero,(ra)
2:
	br	zero,1b
END(nasd_atomic_sub64)
