我们使用的是基于 zynq-7000 的 CPU,因此是 cortex-a9,并且在使用我们正在使用的库 (open-amp) 内的atomic_flags 时遇到了以下问题。
我们使用 SoC 上的第二个 CPU 来执行裸机代码。
禁用 dcache 时,无法再设置原子整数,这是一个为我们触发问题的简单代码:
#define XREG_CONTROL_DCACHE_BIT (0X00000001U<<2U)
#define XREG_CP15_SYS_CONTROL "p15, 0, %0, c1, c0, 0"
#define mfcp(rn) ({uint32_t rval = 0U; \
__asm__ __volatile__(\
"mrc " rn "\n"\
: "=r" (rval)\
);\
rval;\
})
#define mtcp(rn, v) __asm__ __volatile__(\
"mcr " rn "\n"\
: : "r" (v)\
);
static void DCacheDisable(void) {
uint32_t CtrlReg;
/* clean and invalidate the Data cache */
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
CtrlReg &= ~(XREG_CONTROL_DCACHE_BIT);
/* disable the Data cache */
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
int main(void) {
DCacheDisable();
atomic_int flag = 0;
printf("Before\n");
atomic_flag_test_and_set(&flag);
printf("After\n");
}
CPU 对 atomic_flag_test_and_set
执行以下循环:
dmb ish
ldrexb r1, [r3] ; bne jumps here
strexb r0, r2, [r3]
cmp r0, #0
bne -20 ; addr=0x1f011614: main + 0x00000060
dmb ish
但是寄存器r0
始终保持1
。
当省略对 DCacheDisable
的函数调用时,代码完美运行。
我真的找不到任何有关禁用 dcache 和原子标志的信息。
有人知道吗?
工具链:我们使用的是 vitis 2022.2,它附带 arm-xilinx-eabi-gcc.exe (GCC) 11.2.0
。编译器选项为-O2 -std=c11 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard
最佳答案
这在支持缓存的 ARM 平台上很常见。高速缓存行被用作排他锁的临时存储。 ARM 中的术语是 exclusive reserve granule或锁定内存的大小。在具有缓存的系统上,您会发现颗粒是缓存行大小。
因此,在内部,ldrex
和 strex
是作为缓存解析策略的一部分实现的。您可以compare it to cortex-m systems ,其中整个内存空间是一个保留颗粒。
ldrex
/strex
对对于与不属于 AXI 结构的外部设备进行同步是没有用的。如果您想禁用缓存以与 FPGA 接口(interface)一起使用,我认为这行不通。您需要在 FPGA 中实现缓存协议(protocol)。
对于 Cortex-M 系统,没有缓存结构,自定义逻辑实现“全局监视器”。
缓存机制实际上似乎很有用,因为缓存行可以用作事务内存。即,要么整条线都 promise 不 promise 。似乎可以为具有多个指针的结构创建无锁算法。该节点不会锁定整个列表,而只会锁定一个条目。不过,我还没有见过它被这样使用过。我认为主要是因为 ARM 文档建议不要这样做(不要依赖 ERG 大小)。
关于c - 禁用 DCache 将阻止设置atomic_flag,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76207164/