微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM体系架构下的同步操作

ARM体系架构下的同步操作

时间:11-09 来源:互联网 点击:

这一系列函数完成对ptr所指向的内存地址的对应操作,并返回操作之后的值。

bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, ...)type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...)

这两个函数完成对变量的原子比较和交换。

即如果ptr所指向的内存地址存放的值与oldval相同的话,则将其用newval的值替换。

返回bool类型的函数返回比较的结果,相同为true,不同为false;

返回type的函数返回的是ptr指向地址交换前存放的值。

LDREX 和 STREX

独占加载和存储寄存器。

语法

LDREX{cond} Rt, [Rn {, #offset}]STREX{cond} Rd, Rt, [Rn {, #offset}]LDREXB{cond} Rt, [Rn]STREXB{cond} Rd, Rt, [Rn]LDREXH{cond} Rt, [Rn]STREXH{cond} Rd, Rt, [Rn]LDREXD{cond} Rt, Rt2, [Rn]STREXD{cond} Rd, Rt, Rt2, [Rn]

其中:

cond

是一个可选的条件代码(请参阅条件执行)。

Rd

是存放返回状态的目标寄存器。

Rt

是要加载或存储的寄存器。

Rt2

为进行双字加载或存储时要用到的第二个寄存器。

Rn

是内存地址所基于的寄存器。

offset

为应用于Rn中的值的可选偏移量。offset只可用于 Thumb-2 指令中。 如果省略offset,则认为偏移量为 0。

LDREX

LDREX可从内存加载数据。

  • 如果物理地址有共享 TLB 属性,则LDREX会将该物理地址标记为由当前处理器独占访问,并且会清除该处理器对其他任何物理地址的任何独占访问标记。

  • 否则,会标记:执行处理器已经标记了一个物理地址,但访问尚未完毕。

STREX

STREX可在一定条件下向内存存储数据。 条件具体如下:

  • 如果物理地址没有共享 TLB 属性,且执行处理器有一个已标记但尚未访问完毕的物理地址,那么将会进行存储,清除该标记,并在Rd中返回值 0。

  • 如果物理地址没有共享 TLB 属性,且执行处理器也没有已标记但尚未访问完毕的物理地址,那么将不会进行存储,而会在Rd中返回值 1。

  • 如果物理地址有共享 TLB 属性,且已被标记为由执行处理器独占访问,那么将进行存储,清除该标记,并在Rd中返回值 0。

  • 如果物理地址有共享 TLB 属性,但没有标记为由执行处理器独占访问,那么不会进行存储,且会在Rd中返回值 1。

限制

r15 不可用于Rd、Rt、Rt2或Rn中的任何一个。

对于STREX,Rd一定不能与Rt、Rt2或Rn为同一寄存器。

对于 ARM 指令:

  • Rt必须是一个编号为偶数的寄存器,且不能为 r14

  • Rt2必须为R(t+1)

  • 不允许使用offset。

对于 Thumb 指令:

  • r13 不可用于Rd、Rt或Rt2中的任何一个

  • 对于LDREXD,Rt和Rt2不可为同一个寄存器

  • offset的值可为 0-1020 范围内 4 的任何倍数。

用法

利用LDREX和STREX可在多个处理器和共享内存系统之前实现进程间通信。

出于性能方面的考虑,请将相应LDREX指令和STREX指令间的指令数控制到最少。

Note

STREX指令中所用的地址必须要与近期执行次数最多的LDREX指令所用的地址相同。
如果使用不同的地址,则STREX指令的执行结果将不可预知。

体系结构

ARMLDREX和STREX可用于 ARMv6 及更高版本中。

ARMLDREXB、LDREXH、LDREXD、STREXB、STREXD和STREXH可用于 ARMv6K 及更高版本中。

所有这些 32 位 Thumb 指令均可用于 ARMv6T2 及更高版本,但LDREXD和STREXD在 ARMv7-M 架构中不可用。

这些指令均无 16 位版本。

示例

MOV r1, #0x1                ; load the ‘lock taken’ valuetryLDREX r0, [LockAddr]        ; load the lock valueCMP r0, #0                  ; is the lock free?STREXEQ r0, r1, [LockAddr]  ; try and claim the lockCMPEQ r0, #0                ; did this succeed?BNE try                     ; no – try again....                        ; yes – we have the lock

arm/include/asm/atomic.h?v=2.6.33" rel="external nofollow noreferrer" target="_blank">http://lxr.free-electrons.com/source/arch/arm/include/asm/atomic.h?v=2.6.33

/**  arch/arm/include/asm/atomic.h**  Copyright (C) 1996 Russell King.*  Copyright (C) 2002 Deep Blue Solutions Ltd.** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.*/#ifndef __ASM_ARM_ATOMIC_H#define __ASM_ARM_ATOMIC_H#include #include #include #define ATOMIC_INIT(i)  { (i) }#ifdef __KERNEL__/** On ARM, ordinary assignment (str instruction) doesnt clear the local* strex/ldrex monitor on some implementations. The reason we can use it for* atomic_set() is the clrex or dummy strex done on every exception return.*/#define atomic_read(v)  ((v)->counter)#define atomic_set(v,i) (((v)->counter) = (i))#if __LINUX_ARM_ARCH__ >= 6/** ARMv6 UP and SMP safe atomic ops.  We use load exclusive and store exclusive to ensure that these are atomic.  * We may loop to ensure that the update happens.*/static inline void atomic_add(int i, atomic_t *v){unsigned long tmp;int result;__asm__ __volatile__("@ atomic_add\n""1:     ldrex   %0, [%2]\n""       add     %0, %0, %3\n""       strex   %1, %0, [%2]\n""       teq     %1, #0\n""       bne     1b": "=&r" (result), "=&r" (tmp): "r" (&v->counter), "Ir" (i): "cc");}static inline int atomic_add_return(int i, atomic_t *v){unsigned long tmp;int result;smp_mb();__asm__ __volatile__("@ atomic_add_return\n""1:     ldrex   %0, [%2]\n""       add     %0, %0, %3\n""       strex   %1, %0, [%2]\n""       teq     %1, #0\n""       bne     1b": "=&r" (result), "=&r" (tmp): "r" (&v->counter), "Ir" (i): "cc");smp_mb();return result;}static inline void atomic_sub(int i, atomic_t *v){unsigned long tmp;int result;__asm__ __volatile__("@ atomic_sub\n""1:     ldrex   %0, [%2]\n""       sub     %0, %0, %3\n""       strex   %1, %0, [%2]\n""       teq     %1, #0\n""       bne     1b": "=&r" (result), "=&r" (tmp): "r" (&v->counter), "Ir" (i): "cc");}static inline int atomic_sub_return(int i, atomic_t *v){unsigned long tmp;int result;smp_mb();__asm__ __volatile__("@ atomic_sub_return\n""1:     ldrex   %0, [%2]\n""       sub     %0, %0, %3\n""       strex   %1, %0, [%2]\n""       teq     %1, #0\n""       bne     1b": "=&r" (result), "=&r" (tmp): "r" (&v->counter), "Ir" (i): "cc");smp_mb();return result;}static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new){unsigned long oldval, res;smp_mb();do {__asm__ __volatile__("@ atomic_cmpxchg\n""ldrex  %1, [%2]\n""mov    %0, #0\n""teq    %1, %3\n""strexeq %0, %4, [%2]\n": "=&r" (res), "=&r" (oldval): "r" (&ptr->counter), "Ir" (old), "r" (new): "cc");} while (res);smp_mb();return oldval;}static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr){unsigned long tmp, tmp2;__asm__ __volatile__("@ atomic_clear_mask\n""1:     ldrex   %0, [%2]\n""       bic     %0, %0, %3\n""       strex   %1, %0, [%2]\n""       teq     %1, #0\n""       bne     1b": "=&r" (tmp), "=&r" (tmp2): "r" (addr), "Ir" (mask): "cc");}#else /* ARM_ARCH_6 */#ifdef CONFIG_SMP#error SMP not supported on pre-ARMv6 CPUs#endifstatic inline int atomic_add_return(int i, atomic_t *v){unsigned long flags;int val;raw_local_irq_save(flags);val = v->counter;v->counter = val += i;raw_local_irq_restore(flags);return val;}#define atomic_add(i, v)        (void) atomic_add_return(i, v)static inline int atomic_sub_return(int i, atomic_t *v){unsigned long flags;int val;raw_local_irq_save(flags);val = v->counter;v->counter = val -= i;raw_local_irq_restore(flags);return val;}#define atomic_sub(i, v)        (void) atomic_sub_return(i, v)static inline int atomic_cmpxchg(atomic_t *v, int old, int new){int ret;unsigned long flags;raw_local_irq_save(flags);ret = v->counter;if (likely(ret == old))v->counter = new;raw_local_irq_restore(flags);return ret;}static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr){unsigned long flags;raw_local_irq_save(flags);*addr &= ~mask;raw_local_irq_restore(flags);}#endif /* __LINUX_ARM_ARCH__ */#define atomic_xchg(v, new) (xchg(&((v)->counter), new))static inline int atomic_add_unless(atomic_t *v, int a, int u){int c, old;c = atomic_read(v);while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)c = old;return c != u;}#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)#define atomic_inc(v)           atomic_add(1, v)#define atomic_dec(v)           atomic_sub(1, v)#define atomic_inc_and_test(v)  (atomic_add_return(1, v) == 0)#define atomic_dec_and_test(v)  (atomic_sub_return(1, v) == 0)#define atomic_inc_return(v)    (atomic_add_return(1, v))#define atomic_dec_return(v)    (atomic_sub_return(1, v))#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)#define smp_mb__before_atomic_dec()     smp_mb()#define smp_mb__after_atomic_dec()      smp_mb()#define smp_mb__before_atomic_inc()     smp_mb()#define smp_mb__after_atomic_inc()      smp_mb()#include #endif#endif

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top