summaryrefslogtreecommitdiff
path: root/libcpu/arm
diff options
context:
space:
mode:
authorYaochenger <[email protected]>2023-03-23 20:06:50 +0800
committerGitHub <[email protected]>2023-03-23 20:06:50 +0800
commitde4f23748212dbba7d0250fdac3ae583e74fcbed (patch)
treea076ba55e7d4105bd20e473ce4700985daca6243 /libcpu/arm
parent765c2ec5f92e82596e1edc2cab6b1a741fd1cc3e (diff)
[atomic]添加arm与risc-v下的常用原子操作函数 (#7053)
* Update Kconfig * Update trap_gcc.S * Update bsp/hifive1/drivers/SConscript Co-authored-by: Man, Jianting (Meco) <[email protected]> * Update SConscript * [atomic]提交一份arm与risc-v架构下的常用原子操作函数 * 修改变量类型 * 更新rtatomic.h与atomic_port.c * 更新rt-thread\libcpu\arm\common\atomic_port.c * 更新include/rtatomic.h与libcpu/arm/common/SConscript * 更新include/rtatomic.h * 修正格式与Kconfig * 修正格式与文件结构 * 规范文件格式与文件重命名 * 添加测试用例与CI * 添加函数声明 * 修改virt64/SConscript 添加atomic_riscv.c * 1.规范代码风格 * 2.添加RISC-V64原子指令支持 解决在RV64下编译器将32-bit运算结果扩展为64-bit 导致判断错误 * 添加C11标准库原子操作测试 --------- Co-authored-by: Man, Jianting (Meco) <[email protected]>
Diffstat (limited to 'libcpu/arm')
-rw-r--r--libcpu/arm/common/SConscript3
-rw-r--r--libcpu/arm/common/atomic_arm.c184
-rw-r--r--libcpu/arm/common/showmem.c2
3 files changed, 188 insertions, 1 deletions
diff --git a/libcpu/arm/common/SConscript b/libcpu/arm/common/SConscript
index b259a94c94..9333c8de74 100644
--- a/libcpu/arm/common/SConscript
+++ b/libcpu/arm/common/SConscript
@@ -18,6 +18,9 @@ if rtconfig.PLATFORM in ['gcc']:
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
+if not GetDepend('RT_USING_HW_ATOMIC'):
+ SrcRemove(src, 'atomic_arm.c')
+
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/libcpu/arm/common/atomic_arm.c b/libcpu/arm/common/atomic_arm.c
new file mode 100644
index 0000000000..81ada079f3
--- /dev/null
+++ b/libcpu/arm/common/atomic_arm.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-07-27 flybreak the first version
+ */
+
+#include <rtthread.h>
+
+/**
+ \brief LDR Exclusive (32 bit)
+ \details Executes a exclusive LDR instruction for 32 bit values.
+ \param [in] ptr Pointer to data
+ \return value of type uint32_t at (*ptr)
+ */
+#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
+#define __LDREXW (rt_atomic_t)__builtin_arm_ldrex
+#elif defined(__ARMCC_VERSION) /* ARM Compiler V5 */
+#if __ARMCC_VERSION < 5060020
+#define __LDREXW(ptr) ((rt_atomic_t ) __ldrex(ptr))
+#else
+#define __LDREXW(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((rt_atomic_t ) __ldrex(ptr)) _Pragma("pop")
+#endif
+#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
+_Pragma("inline=forced") __intrinsic rt_atomic_t __LDREXW(volatile rt_atomic_t volatile *ptr)
+{
+ return __LDREX((unsigned long *)ptr);
+}
+#elif defined (__GNUC__) /* GNU GCC Compiler */
+__attribute__((always_inline)) static inline rt_atomic_t __LDREXW(volatile rt_atomic_t *addr)
+{
+ rt_atomic_t result;
+
+ __asm volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) );
+ return result;
+}
+#endif
+
+/**
+ \brief STR Exclusive (32 bit)
+ \details Executes a exclusive STR instruction for 32 bit values.
+ \param [in] value Value to store
+ \param [in] ptr Pointer to location
+ \return 0 Function succeeded
+ \return 1 Function failed
+ */
+#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
+#define __STREXW (rt_atomic_t)__builtin_arm_strex
+#elif defined(__ARMCC_VERSION) /* ARM Compiler V5 */
+#if __ARMCC_VERSION < 5060020
+#define __STREXW(value, ptr) __strex(value, ptr)
+#else
+#define __STREXW(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop")
+#endif
+#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
+_Pragma("inline=forced") __intrinsic rt_atomic_t __STREXW(rt_atomic_t value, volatile rt_atomic_t *ptr)
+{
+ return __STREX(value, (unsigned long *)ptr);
+}
+#elif defined (__GNUC__) /* GNU GCC Compiler */
+__attribute__((always_inline)) static inline rt_atomic_t __STREXW(volatile rt_atomic_t value, volatile rt_atomic_t *addr)
+{
+ rt_atomic_t result;
+
+ __asm volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
+ return result;
+}
+#endif
+
+rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(oldval, ptr)) != 0U);
+ return *ptr;
+}
+
+void rt_hw_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val)
+{
+ do
+ {
+ __LDREXW(ptr);
+ } while ((__STREXW(val, ptr)) != 0U);
+}
+
+rt_atomic_t rt_hw_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(oldval + val, ptr)) != 0U);
+ return oldval;
+}
+
+rt_atomic_t rt_hw_atomic_sub(volatile rt_atomic_t *ptr, rt_atomic_t val)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(oldval - val, ptr)) != 0U);
+ return oldval;
+}
+
+rt_atomic_t rt_hw_atomic_and(volatile rt_atomic_t *ptr, rt_atomic_t val)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(oldval & val, ptr)) != 0U);
+ return oldval;
+}
+
+rt_atomic_t rt_hw_atomic_or(volatile rt_atomic_t *ptr, rt_atomic_t val)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(oldval | val, ptr)) != 0U);
+ return oldval;
+}
+
+rt_atomic_t rt_hw_atomic_xor(volatile rt_atomic_t *ptr, rt_atomic_t val)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(oldval ^ val, ptr)) != 0U);
+ return oldval;
+}
+
+rt_atomic_t rt_hw_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(val, ptr)) != 0U);
+ return oldval;
+}
+
+void rt_hw_atomic_flag_clear(volatile rt_atomic_t *ptr)
+{
+ do
+ {
+ __LDREXW(ptr);
+ } while ((__STREXW(0, ptr)) != 0U);
+}
+
+rt_atomic_t rt_hw_atomic_flag_test_and_set(volatile rt_atomic_t *ptr)
+{
+ rt_atomic_t oldval;
+ do
+ {
+ oldval = __LDREXW(ptr);
+ } while ((__STREXW(1, ptr)) != 0U);
+ return oldval;
+}
+
+rt_atomic_t rt_hw_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr, rt_atomic_t *old, rt_atomic_t new)
+{
+ rt_atomic_t result;
+ rt_atomic_t temp = *old;
+ do
+ {
+ result = __LDREXW(ptr);
+ if (result != temp)
+ {
+ *old = result;
+ __STREXW(result, ptr);
+ break;
+ }
+ } while ((__STREXW(new, ptr)) != 0U);
+ return (result == temp);
+}
diff --git a/libcpu/arm/common/showmem.c b/libcpu/arm/common/showmem.c
index 2ece137a40..60a18a1969 100644
--- a/libcpu/arm/common/showmem.c
+++ b/libcpu/arm/common/showmem.c
@@ -10,7 +10,7 @@
#include <rtthread.h>
-void rt_hw_show_memory(rt_uint32_t addr, rt_uint32_t size)
+void rt_hw_show_memory(rt_uint32_t addr, rt_size_t size)
{
unsigned int i = 0, j = 0;