mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-20 17:44:20 +08:00
[atomic]添加arm与risc-v下的常用原子操作函数 (#7053)
* Update Kconfig * Update trap_gcc.S * Update bsp/hifive1/drivers/SConscript Co-authored-by: Man, Jianting (Meco) <920369182@qq.com> * 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) <920369182@qq.com>
This commit is contained in:
co-authored by
Man, Jianting (Meco) <920369182@qq.com>
parent
765c2ec5f9
commit
de4f237482
@@ -5,6 +5,10 @@ config RT_USING_CACHE
|
||||
bool
|
||||
default n
|
||||
|
||||
config RT_USING_HW_ATOMIC
|
||||
bool
|
||||
default n
|
||||
|
||||
config ARCH_CPU_BIG_ENDIAN
|
||||
bool
|
||||
|
||||
@@ -47,6 +51,7 @@ config ARCH_ARM_CORTEX_M3
|
||||
bool
|
||||
select ARCH_ARM_CORTEX_M
|
||||
select RT_USING_CPU_FFS
|
||||
select RT_USING_HW_ATOMIC
|
||||
|
||||
config ARCH_ARM_MPU
|
||||
bool
|
||||
@@ -57,21 +62,25 @@ config ARCH_ARM_CORTEX_M4
|
||||
bool
|
||||
select ARCH_ARM_CORTEX_M
|
||||
select RT_USING_CPU_FFS
|
||||
select RT_USING_HW_ATOMIC
|
||||
|
||||
config ARCH_ARM_CORTEX_M7
|
||||
bool
|
||||
select ARCH_ARM_CORTEX_M
|
||||
select RT_USING_CPU_FFS
|
||||
select RT_USING_CACHE
|
||||
select RT_USING_HW_ATOMIC
|
||||
|
||||
config ARCH_ARM_CORTEX_M33
|
||||
bool
|
||||
select ARCH_ARM_CORTEX_M
|
||||
select RT_USING_CPU_FFS
|
||||
select RT_USING_HW_ATOMIC
|
||||
|
||||
config ARCH_ARM_CORTEX_R
|
||||
bool
|
||||
select ARCH_ARM
|
||||
select RT_USING_HW_ATOMIC
|
||||
|
||||
config ARCH_ARM_MMU
|
||||
bool
|
||||
@@ -107,6 +116,7 @@ config ARCH_ARM_CORTEX_A
|
||||
select ARCH_ARM
|
||||
select ARCH_ARM_MMU
|
||||
select RT_USING_CPU_FFS
|
||||
select RT_USING_HW_ATOMIC
|
||||
|
||||
if ARCH_ARM_CORTEX_A
|
||||
config RT_SMP_AUTO_BOOT
|
||||
@@ -156,6 +166,7 @@ config ARCH_ARMV8
|
||||
bool
|
||||
select ARCH_ARM
|
||||
select ARCH_ARM_MMU
|
||||
select RT_USING_HW_ATOMIC
|
||||
|
||||
config ARCH_MIPS
|
||||
bool
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S')
|
||||
CPPPATH = [cwd]
|
||||
ASFLAGS = ' -I ' + cwd
|
||||
|
||||
if not GetDepend('RT_USING_HW_ATOMIC'):
|
||||
SrcRemove(src, 'atomic_riscv.c')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS)
|
||||
|
||||
Return('group')
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-14 WangShun first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
rt_atomic_t rt_hw_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoswap.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoswap.d %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_atomic_t rt_hw_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoadd.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoadd.d %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_atomic_t rt_hw_atomic_sub(volatile rt_atomic_t *ptr, rt_atomic_t val)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
val = -val;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoadd.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoadd.d %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_atomic_t rt_hw_atomic_xor(volatile rt_atomic_t *ptr, rt_atomic_t val)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoxor.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoxor.d %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_atomic_t rt_hw_atomic_and(volatile rt_atomic_t *ptr, rt_atomic_t val)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoand.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoand.d %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_atomic_t rt_hw_atomic_or(volatile rt_atomic_t *ptr, rt_atomic_t val)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoor.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoor.d %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoxor.w %0, x0, (%1)" : "=r"(result) : "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoxor.d %0, x0, (%1)" : "=r"(result) : "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
void rt_hw_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoswap.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoswap.d %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
rt_atomic_t rt_hw_atomic_flag_test_and_set(volatile rt_atomic_t *ptr)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
rt_atomic_t temp = 1;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoor.w %0, %1, (%2)" : "=r"(result) : "r"(temp), "r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoor.d %0, %1, (%2)" : "=r"(result) : "r"(temp), "r"(ptr) : "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
void rt_hw_atomic_flag_clear(volatile rt_atomic_t *ptr)
|
||||
{
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile ("amoand.w %0, x0, (%1)" : "=r"(result) :"r"(ptr) : "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile ("amoand.d %0, x0, (%1)" : "=r"(result) :"r"(ptr) : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
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 tmp = *old;
|
||||
rt_atomic_t result;
|
||||
#if __riscv_xlen == 32
|
||||
asm volatile(
|
||||
" fence iorw, ow\n"
|
||||
"1: lr.w.aq %[result], (%[ptr])\n"
|
||||
" bne %[result], %[tmp], 2f\n"
|
||||
" sc.w.rl %[tmp], %[new], (%[ptr])\n"
|
||||
" bnez %[tmp], 1b\n"
|
||||
" li %[result], 1\n"
|
||||
" j 3f\n"
|
||||
" 2:sw %[result], (%[old])\n"
|
||||
" li %[result], 0\n"
|
||||
" 3:\n"
|
||||
: [result]"+r" (result), [tmp]"+r" (tmp), [ptr]"+r" (ptr)
|
||||
: [new]"r" (new), [old]"r"(old)
|
||||
: "memory");
|
||||
#elif __riscv_xlen == 64
|
||||
asm volatile(
|
||||
" fence iorw, ow\n"
|
||||
"1: lr.d.aq %[result], (%[ptr])\n"
|
||||
" bne %[result], %[tmp], 2f\n"
|
||||
" sc.d.rl %[tmp], %[new], (%[ptr])\n"
|
||||
" bnez %[tmp], 1b\n"
|
||||
" li %[result], 1\n"
|
||||
" j 3f\n"
|
||||
" 2:sd %[result], (%[old])\n"
|
||||
" li %[result], 0\n"
|
||||
" 3:\n"
|
||||
: [result]"+r" (result), [tmp]"+r" (tmp), [ptr]"+r" (ptr)
|
||||
: [new]"r" (new), [old]"r"(old)
|
||||
: "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S')
|
||||
src = src + ['../common/atomic_riscv.c']
|
||||
CPPPATH = [cwd]
|
||||
ASFLAGS = ''
|
||||
|
||||
|
||||
Reference in New Issue
Block a user