blob: 9ec9b26468828c24004ec4226d117c5645bcd7cc [file] [log] [blame]
/*****************************************************************************
*
* parisc/atomic.s
*
* $Id$
*
*****************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2002-2006 Rogue Wave Software.
*
* 2002 Copyright Hewlett-Packard Company
*
* Routines for atomic increment and decrement of int32_t values
*
* int32_t __rw_atomic_incr32(int32_t *addr);
* int32_t __rw_atomic_decr32(int32_t *addr);
* int32_t __rw_atomic_xchg32(int32_t *addr, int32_t val);
*
*****************************************************************************/
#if !defined (_PA_RISC2_0)
# define _PA_RISC2_0
#endif // _PA_RISC2_0
#define addr arg0
#define swap_val arg1
#define tmp1 r22
#define tmp2 r20
#define interlock_val r31
/*
* For pre HP-UX 11.0 compilers, this will need to change to C comment
* Style given the compilers are broken and don't use ## correctly
*/
#define LABEL(a,b) .label a##b
#define LABEL_REF(a,b) a##b
#ifdef __LP64__
.level 2.0W
#define LDD ldd
#define STD std
#define STACK_ADJUST -16
#define FRAME_SIZE 48
#define RP_OFFSET -144
#define LOCK_OFFSET -120
#define ADDR_OFFSET -112
#define SWAP_OFFSET -104
#define DP r27
#define SAVE_DATA_POINTER std DP,-128(sp)
#define RESTORE_DATA_POINTER ldd -128(sp),DP
#define RETURN_SEQ(tmpreg) bve (rp) ! ldo -128(sp),sp
#define SAVE_ARG_POINTER ldo -48(sp),r29
#else
#ifdef _PA_RISC2_0
.level 2.0
#define RETURN_SEQ(tmpreg) bve (rp) ! ldo -128(sp),sp
#else
.level 1.1
error, can't use this code on PA-RISC 1.1 implementations
#endif
#define LDD ldw
#define STD stw
#define STACK_ADJUST -20
#define FRAME_SIZE 16
#define RP_OFFSET -148
#define SWAP_OFFSET -44
#define LOCK_OFFSET -40
#define ADDR_OFFSET -36
#define DP r19
#define SAVE_DATA_POINTER stw DP,-32(sp)
#define RESTORE_DATA_POINTER ldw -32(sp),DP
#define SAVE_ARG_POINTER
#endif
#define __rwInterlocked_BODY(sn, BODY) \
STD rp,STACK_ADJUST(sp) /* store return pointer */ !\
ldo 128(sp),sp /* adjust stack */ !\
LABEL(sn,_top) !\
ldcws,co 0(addr),interlock_val /* grab lock */ !\
/* if lock held, then spin */ !\
cmpb,=,n r0,interlock_val, LABEL_REF(sn,_spin_top) !\
/* branch pred not taken */ !\
LDD RP_OFFSET(sp),rp /* load return pointer */ !\
/* Free variables are */ !\
/* tmp1, tmp2 */ !\
BODY /* Do operation */ !\
RETURN_SEQ(tmp1) /* return sequence */ !\
!\
LABEL(sn,_spin_top) !\
/* !\
* Did not get the lock, spin for it for a little while !\
*/ !\
depwi,z 1,15,1,tmp2 /* spin 65536 times, then go to higher */ !\
/* level code */ !\
ldws 0(addr), tmp1 /* look at lock value */ !\
LABEL(sn,_loop) !\
cmpb,<> tmp1, r0, LABEL_REF(sn,_top) /* got the lock, then try again */ !\
/* atomically, predict not taken */ !\
nop !\
addib,<>,n -1, tmp2, LABEL_REF(sn,_loop) /* see if lock is free again */ !\
ldws 0(addr), tmp1 /* look at lock value */ !\
!\
cmpb,<> r0,tmp2,LABEL_REF(sn,_top) /* if exited due to getting lock*/ !\
/* then try again atomically */ !\
/* predicted not taken */ !\
nop !\
!\
/* !\
* Did not get the lock spinning, so yield the processor to allow !\
* someone else a shot !\
*/ !\
STD addr,ADDR_OFFSET(sp) /* save the address to access */ !\
STD swap_val,SWAP_OFFSET(sp) /* save the swap value */ !\
SAVE_ARG_POINTER !\
.call rtnval=gr !\
b,l sched_yield,rp /* yield the processor and try again */ !\
SAVE_DATA_POINTER !\
LDD SWAP_OFFSET(sp),swap_val /* restore the address of the lock */ !\
LDD ADDR_OFFSET(sp),addr /* restore the address to access */ !\
RESTORE_DATA_POINTER !\
b LABEL_REF(sn,_spin_top) /* Try again */ !\
nop
;
; Export all of the interfaces
;
.space $TEXT$
.subspa $CODE$
.export __rw_atomic_incr32,entry,argw0=gr,rtnval=gr,LONG_RETURN
.export __rw_atomic_decr32,entry,argw0=gr,rtnval=gr,LONG_RETURN
.export __rw_atomic_xchg32,entry,argw0=gr,rtnval=gr,LONG_RETURN
;-------------------------------------------------------------------------------
; int32_t __rw_atomic_incr32(int32_t *addr);
; arg0 = int32_t *addr
;
; This routine atomically increments the passed in value and returns
; the newly incremented value. It is atomic with respect to other
; __rw_atomic_incr32 calls and with respect to other __rw_atomic_decr32
; calls.
;-------------------------------------------------------------------------------
#define IncrementBODY \
ldo 1(interlock_val),ret0 /* adjust value */ !\
stw ret0,0(addr) /* store new result, release lock */
.code
__rw_atomic_incr32
.proc
.import sched_yield
.callinfo caller,frame=FRAME_SIZE,save_rp,args_saved
__rwInterlocked_BODY(ii, IncrementBODY)
.procend
;-------------------------------------------------------------------------------
; int32_t __rw_atomic_decr32(int32_t *addr);
; arg0 = int32_t *addr
;
; This routine atomically decrements the passed in value and returns
; the newly decremented value. It is atomic with respect to other
; __rw_atomic_decr32 calls and with respect to other __rw_atomic_incr32
; calls.
;-------------------------------------------------------------------------------
#define DecrementBODY \
ldo -1(interlock_val),ret0 /* adjust value */ !\
stw ret0,0(addr) /* store new result,release lock */
__rw_atomic_decr32
.proc
.import sched_yield
.callinfo caller,frame=FRAME_SIZE,save_rp,args_saved
__rwInterlocked_BODY(id, DecrementBODY)
.procend
#define ExchangeBODY \
ldo 0(interlock_val),ret0 /* return current value */ !\
stw swap_val, 0(addr) /* store new value, release lock */
__rw_atomic_xchg32
.proc
.import sched_yield
.callinfo caller,frame=FRAME_SIZE,save_rp,args_saved
__rwInterlocked_BODY(is, ExchangeBODY)
.procend