潮声隔雨深 · 2019年07月16日

device memory bufferable 怎样保证数据的正确性?

对于device memory,如果在write command之后紧跟了一个read command,那data 如果存到了write buffer里面,要怎么保证读取数据的正确呢?

3 个回答 得票排序 · 时间排序
傻孩子(GorgonMeducer) · 2019年08月08日

由于题主没有给出明确的运行环境信息,我只能根据自己的知识局限,假设这是讨论Arm环境下的Memory Model。基于这个前提:

Device Memory实际上是用来描述一类特殊的存储器(或者映射到指定地址空间中的寄存器),这些特殊就特殊在,无论是你读还是写,除了读写本身的功能以外,还会有“副作用”。举个最直接的例子:很多中断的状态寄存器保存了中断Flag,这些Flag往往是写1清零的,或者是读取寄存器就会自动讲这些Flag清零。

如果一段地址空间被标记为Device Memory,它立即就表示:在这段空间里执行代码(Instruction Fetch)是“后果自付的”;CPU是不允许“自作聪明的进行预读”的——这应该很好理解吧?如果CPU自作聪明预读了寄存器导致FLAG被清除了,这冤屈找谁说去。

既然读写操作有了“副作用”,你自然会小心翼翼,不希望自己的操作出什么幺蛾子,也不希望总线系统的硬件“自作聪明”,比如:

  • 自动帮你多个对存储器操作的顺序改了(Re-ordering)
  • 自动帮你把对同一段地址的同类操作都给你合并了(Gathering)
  • 写操作的时候,只把值送到了write buffer里,而实际并没有写到目标存储器里的时候就急急忙忙跟processor报告“完成了”(Early Write Acknowledgement)

如果我们用G,R,E来表示这几类“骚操作”,nG,nR, nE表示禁止对应的骚操作。
那么,Device Memory实际上就有了以下几种组合:

Device-nGnRnE - 史上最严
Device-nGnRE
Device-nGRE
Device-GRE - 山坡放羊


洋洋洒洒说了这么多,我们来回答题主的问题:

首先,如果题主不喜欢write buffer,那么可以把对应的Device属性改为nE,也就是关闭write buffer——比如使用史上最严的Device-nGnRnE版本。具体怎么做,参考MPU配置。
其次,如果题主确实需要用write buffer,这里要告诉你一个好消息,如果你对一个开了write buffer的地址进行写操作,然后立即紧跟着一个读操作,硬件系统为了保证逻辑的正确性,会确保第一个写操作的数据“确确实实”的被写入到了对应的地址上,然后才会执行读取操作。这个骚操作就是传说中大名鼎鼎的“Dummy read”。

Dummy Read是一个非常有用的功能,它一般用于确保对寄存器的配置“落实到了基层”——比如你在中断处理程序里试图关闭中断源,以防止这类“level的中断源”一直触发,你就需要在退出中断处理程序前,写对应的外设寄存器,并使用“Dummy read”大法来确保你的“关怀落实到了基层”。

最后:题主说的Device Memory究竟是哪种呢?开没开对R的支持啊?如果开了,或者根本不确定是否开了,那1楼说的Barrier也是要加的。具体参考这个文档:

http://infocenter.arm.com/hel...

希望这个答案让你满意。

极术小姐姐 · 2019年07月16日

读写的顺序,总线是不会保证的,因为对AXI协议来说,读写通道是并行的,互相不影响的。

对于CPU而言,可以通过memory barrier指令去保证读写之间的顺序,它可以保证写操作完成了之后,也就是收到response了,才发出读操作;对于其他类型的master,则需要自己保证读写顺序。

djygrdzh · 2019年10月03日

A device or strongly ordered load must stall in dc3 if there are device or strongly ordered stores in the STB or BIU(includes write buffer).此处无需地址相同。

此外,内存模型定义中的bufferable和问题中的write buffer是完全不同的概念。对于non-bufferable属性,处理器发出的传输,所有的总线及其缓冲有义务不提前回应。只有最后一层的从设备才能给出响应,而不是中间被缓冲并提前回应。这样,在设置控制寄存器这样的场景下,命令下到了最终设备,然后再继续下一个命令。write buffer仅仅是保证命令在总线中传递的次序,而不能保证命令起作用后,下一条命令才发出。
这里,并不需要barrier指令来帮忙。

你的回答