os/kernelhwsrv/kernel/eka/common/arm/atomic_8_16_v6.h
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\common\arm\atomic_8_16_v6.h
    15 // 8 and 16 bit atomic operations on V6 processors using LDREX/STREX and shifts
    16 // Must use these user side so that it will work with data paging.
    17 // 
    18 //
    19 
    20 #include "atomic_ops.h"
    21 
    22 #if defined(__CPU_ARM_HAS_LDREX_STREX_V6K) || !defined(__CPU_ARM_HAS_LDREX_STREX)
    23 #error 8/16 bit atomic operations using LDREX/STREX
    24 #endif
    25 
    26 #ifdef __BARRIERS_NEEDED__
    27 #error Barriers not supported on V6/V5, only V6K/V7
    28 #endif
    29 
    30 #if __DATA_SIZE__!=8 && __DATA_SIZE__!=16
    31 #error Unsupported data size
    32 #endif
    33 
    34 #if defined(__OP_LOAD__)
    35 #error Load operation not defined
    36 
    37 #elif defined(__OP_STORE__)
    38 #error Store operation not defined
    39 
    40 #elif defined(__OP_RMW1__)
    41 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
    42 	{
    43 	// R0=a, R1=v
    44 	// return value in R0
    45 	// just fall through
    46 	}
    47 
    48 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
    49 	{
    50 	// R0=a, R1=v
    51 	// return value in R0
    52 	// just fall through
    53 	}
    54 
    55 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
    56 	{
    57 	// R0=a, R1=v
    58 	// return value in R0
    59 	// just fall through
    60 	}
    61 
    62 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
    63 	{
    64 	// R0=a, R1=v
    65 	// return value in R0
    66 	asm("bic r12, r0, #3 ");
    67 	asm("and r3, r0, #3 ");
    68 	asm("stmfd sp!, {r4-r5} ");
    69 	asm("movs r4, r3, lsl #3 ");	// r4 = bit offset of data in word
    70 #if __DATA_SIZE__==16
    71 	asm("eor r4, r4, #16 ");		// r4 = right rotate to take hword of interest to top (0->16, 2->0)
    72 	asm("mov r5, r4 ");
    73 #elif __DATA_SIZE__==8
    74 	asm("add r4, r4, #8 ");
    75 	asm("and r4, r4, #31 ");		// right rotate to take byte of interest to top byte (0->8, 1->16, 2->24, 3->0)
    76 	asm("rsb r5, r4, #32 ");
    77 	asm("and r5, r5, #31 ");		// right rotate to take top byte to byte of interest (0->8, 1->16, 2->24, 3->0)
    78 #endif
    79 #if defined(__OP_AND__)
    80 	asm("mvn r1, r1 ");
    81 	asm("mvn r1, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));	// v in upper bits of r1, 1's in lower bits
    82 #endif
    83 	asm("1: ");
    84 	LDREX(0,12);
    85 	asm("mov r0, r0, ror r4 ");		// rotate so desired data is at top
    86 #if defined(__OP_SWP__)
    87 	asm("orr r2, r1, r0, lsl #%a0" : : "i" (__DATA_SIZE__));
    88 	asm("mov r2, r2, ror #%a0" : : "i" (__DATA_SIZE__));
    89 #elif defined(__OP_ADD__)
    90 	asm("add r2, r0, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));
    91 #elif defined(__OP_AND__)
    92 	asm("and r2, r0, r1 ");
    93 #elif defined(__OP_IOR__)
    94 	asm("orr r2, r0, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));
    95 #elif defined(__OP_XOR__)
    96 	asm("eor r2, r0, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));
    97 #endif
    98 	asm("mov r2, r2, ror r5 ");		// rotate back
    99 	STREX(3,2,12);
   100 	asm("cmp r3, #0 ");
   101 	asm("bne 1b ");
   102 	asm("mov r0, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__));	// shift return value so data is at bottom
   103 	asm("ldmfd sp!, {r4-r5} ");
   104 	__JUMP(,lr);
   105 	}
   106 
   107 
   108 #elif defined(__OP_CAS__)
   109 extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
   110 	{
   111 	// R0=a, R1=q, R2=v
   112 	// return value in R0
   113 	// just fall through
   114 	}
   115 
   116 extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
   117 	{
   118 	// R0=a, R1=q, R2=v
   119 	// return value in R0
   120 	// just fall through
   121 	}
   122 
   123 extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
   124 	{
   125 	// R0=a, R1=q, R2=v
   126 	// return value in R0
   127 	// just fall through
   128 	}
   129 
   130 extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
   131 	{
   132 	// R0=a, R1=q, R2=v
   133 	// return value in R0
   134 	asm("bic r12, r0, #3 ");
   135 	asm("and r3, r0, #3 ");
   136 	asm("stmfd sp!, {r4-r6} ");
   137 	asm("movs r4, r3, lsl #3 ");	// r4 = bit offset of data in word
   138 	__LDR_INST__( ," r6, [r1] ");	// r6 = expected value
   139 #if __DATA_SIZE__==16
   140 	asm("mov r5, r4 ");				// r5 = right rotate to take bottom hword to hword of interest (0->0, 2->16)
   141 	asm("eor r4, r4, #16 ");		// r4 = right rotate to take hword of interest to top (0->16, 2->0)
   142 #elif __DATA_SIZE__==8
   143 	asm("rsb r5, r4, #32 ");
   144 	asm("and r5, r5, #31 ");		// right rotate to take bottom byte to byte of interest (0->0, 1->24, 2->16, 3->8)
   145 	asm("add r4, r4, #8 ");
   146 	asm("and r4, r4, #31 ");		// right rotate to take byte of interest to top byte (0->8, 1->16, 2->24, 3->0)
   147 #endif
   148 	asm("1: ");
   149 	LDREX(0,12);
   150 	asm("mov r0, r0, ror r4 ");		// rotate so desired data is at top
   151 	asm("cmp r6, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__));		// check desired data against expected value *q
   152 	asm("bne 2f ");					// if no match, give up
   153 	asm("orr r0, r2, r0, lsl #%a0" : : "i" (__DATA_SIZE__));	// substitute value v into bottom bits of r0, replacing original
   154 	asm("mov r0, r0, ror r5 ");		// rotate back (bottom byte/hword goes to byte/hword of interest)
   155 	STREX(3,0,12);
   156 	asm("cmp r3, #0 ");
   157 	asm("bne 1b ");
   158 	asm("2: ");
   159 	asm("movne r0, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__));	// shift return value so data is at bottom
   160 	__STR_INST__(ne, "r0, [r1] ");	// update *q with observed value
   161 	asm("ldmfd sp!, {r4-r6} ");
   162 	asm("movne r0, #0 ");			// if *a not updated return FALSE
   163 	asm("moveq r0, #1 ");			// if *a updated return TRUE
   164 	__JUMP(,lr);
   165 	}
   166 
   167 
   168 #elif defined(__OP_AXO__)
   169 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   170 	{
   171 	// R0=a, R1=u, R2=v
   172 	// return value in R0
   173 	// just fall through
   174 	}
   175 
   176 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   177 	{
   178 	// R0=a, R1=u, R2=v
   179 	// return value in R0
   180 	// just fall through
   181 	}
   182 
   183 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   184 	{
   185 	// R0=a, R1=u, R2=v
   186 	// return value in R0
   187 	// just fall through
   188 	}
   189 
   190 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   191 	{
   192 	// R0=a, R1=u, R2=v
   193 	// return value in R0
   194 	asm("and r3, r0, #3 ");
   195 	asm("bic r12, r0, #3 ");
   196 	asm("stmfd sp!, {r4-r5} ");
   197 	asm("mvn r1, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));	// ~u in upper bits of r1, 1's in lower bits
   198 	asm("movs r4, r3, lsl #3 ");	// r4 = bit offset of data in word
   199 	asm("mov r1, r1, lsr #%a0" : : "i" (32-__DATA_SIZE__));	// ~u in lower bits of r1, zero extended
   200 	asm("1: ");
   201 	LDREX(0,12);
   202 	asm("bic r5, r0, r1, lsl r4 ");	// r5 = r0 & u in relevant bit positions, other bit positions unchanged
   203 	asm("eor r5, r5, r2, lsl r4 ");
   204 	STREX(3,5,12);
   205 	asm("cmp r3, #0 ");
   206 	asm("bne 1b ");
   207 	asm("mov r0, r0, lsr r4 ");		// shift original value so byte/hword of interest is at the bottom
   208 	asm("ldmfd sp!, {r4-r5} ");
   209 #if __DATA_SIZE__==16
   210 	asm("bic r0, r0, #0xff000000 ");	// mask upper 16 bits
   211 	asm("bic r0, r0, #0x00ff0000 ");
   212 #elif __DATA_SIZE__==8
   213 	asm("and r0, r0, #0xff ");			// mask upper 24 bits
   214 #endif
   215 	__JUMP(,lr);
   216 	}
   217 
   218 
   219 #elif defined(__OP_RMW3__)
   220 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   221 	{
   222 	// R0=a, R1=t, R2=u, R3=v
   223 	// return value in R0
   224 	// just fall through
   225 	}
   226 
   227 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   228 	{
   229 	// R0=a, R1=t, R2=u, R3=v
   230 	// return value in R0
   231 	// just fall through
   232 	}
   233 
   234 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   235 	{
   236 	// R0=a, R1=t, R2=u, R3=v
   237 	// return value in R0
   238 	// just fall through
   239 	}
   240 
   241 extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
   242 	{
   243 	// R0=a, R1=t, R2=u, R3=v
   244 	// return value in R0
   245 	asm("bic r12, r0, #3 ");
   246 	asm("stmfd sp!, {r4-r7} ");
   247 	asm("and r4, r0, #3 ");
   248 	asm("movs r4, r4, lsl #3 ");	// r4 = bit offset of data in word
   249 #if __DATA_SIZE__==16
   250 	asm("eor r4, r4, #16 ");		// r4 = right rotate to take hword of interest to top (0->16, 2->0)
   251 	asm("mov r5, r4 ");				// r5 = right rotate to undo r4
   252 #elif __DATA_SIZE__==8
   253 	asm("add r4, r4, #8 ");
   254 	asm("and r4, r4, #31 ");		// right rotate to take byte of interest to top byte (0->8, 1->16, 2->24, 3->0)
   255 	asm("rsb r5, r4, #32 ");
   256 	asm("and r5, r5, #31 ");		// right rotate to take top byte to byte of interest (0->8, 1->16, 2->24, 3->0)
   257 #endif
   258 	asm("1: ");
   259 	LDREX(0,12);
   260 	asm("mov r0, r0, ror r4 ");		// rotate so desired data is at top
   261 #if	defined(__OP_TAU__)
   262 	asm("cmp r1, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__));	// t - byte/hword of interest
   263 	asm("addls r6, r0, r2, lsl #%a0" : : "i" (32-__DATA_SIZE__));	// if t<=*a add u
   264 	asm("addhi r6, r0, r3, lsl #%a0" : : "i" (32-__DATA_SIZE__));	// if t>*a add v
   265 #elif	defined(__OP_TAS__)
   266 	asm("cmp r1, r0, asr #%a0" : : "i" (32-__DATA_SIZE__));	// t - byte/hword of interest
   267 	asm("addle r6, r0, r2, lsl #%a0" : : "i" (32-__DATA_SIZE__));	// if t<=*a add u
   268 	asm("addgt r6, r0, r3, lsl #%a0" : : "i" (32-__DATA_SIZE__));	// if t>*a add v
   269 #endif
   270 	asm("mov r6, r6, ror r5 ");		// rotate back
   271 	STREX(7,6,12);
   272 	asm("cmp r7, #0 ");
   273 	asm("bne 1b ");
   274 	asm("ldmfd sp!, {r4-r7} ");
   275 #if	defined(__OP_TAU__)
   276 	asm("mov r0, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__));	// shift return value so data is at bottom
   277 #elif	defined(__OP_TAS__)
   278 	asm("mov r0, r0, asr #%a0" : : "i" (32-__DATA_SIZE__));	// shift return value so data is at bottom
   279 #endif
   280 	__JUMP(,lr);
   281 	}
   282 
   283 #endif
   284 
   285 // Second inclusion undefines temporaries
   286 #include "atomic_ops.h"