内存映射有不同的类型.每种类型都定义了如何进行内存访问以及读/写的可能重新排序.
在这种情况下,例如当指令序列high1 = read(base+4); low = read(base);
由CPU(如low = read(base); high1 = read(base+4);
)执行时,重新排序.从性能的Angular 来看,这是完全合理的.在CPUtry 执行while (high2 != high1);
的阶段,通常情况下,分配给哪个寄存器的第一个"低"或"高1"并不重要.CPU基本上不知道两个单词之间的相互依赖关系.
对于这种64位值的情况,我们应该采取额外的步骤来防止CPU删除这个寄存器依赖项.
第一种也是"最正确的"方法是将计时器映射为"设备"内存.通常,所有硬件映射内存都是"设备"内存设备的内存映射保证了严格的内存顺序.所以CPU不会对内存读取(或写入,或两者)进行任何重新排序,它总是high1
、low
、high2
.设备内存也是不可缓存的.在这种情况下,这并不重要,但对于使用DMA的东西来说,它可以从维护缓存一致性中节省内存.作为结论,在这种情况下,任何sync barriers for 'device' memory are redundant.
如果你想找麻烦,硬件可能会被映射为"通用"/"通用"内存.
high1 = read(base+4); low = read(base);
被重新排序并作为low = read(base); high1 = read(base+4);
执行
- 低读数为
9999
,读数完成后,定时器递增.
- 现在计时器是
0001-0000
- 高的读数为
0001
- 我们有
0001-9999
个
所以,正如我所看到的,有必要防止读数high1
和low
,以及low
和high2
的重新排序,因为在这两种情况下,我们都可以得到0001-9999
种情况(对于第二种情况,高1=0000,高2=0000,低=0000,在high
中缺少0001
).
我得说
do {
high1 = read(base+4);
asm volatile("dmb sy");
low = read(base);
asm volatile("dmb sy");
high2 = read(base+4);
// asm volatile("dmb sy"); This looks like excessive
} while (high2 != high1);
PS:看起来你不需要像sy
这样严格的订单,非常小的一个,保证在特定CPU上的订单应该足够了.