关于Cache与WriteBuffer的原理可以查阅相关博客或书籍。这里我只想讨论哪种情况下不能使用Cache与WriteBuffer,以及使用Cache与WriteBuffer时给存储系统带来的一致性问题以及解决方法。
使用Cache通常需要存储器件具有下面的特性:
a.读操作将返回最后一次写入的内容,而且没有其它的副作用
b.写操作除了影响目标单元的内容外,没有其它的副作用
c.对同一目标单元的两次连续读取操作将得到相同的结果
d.对同一目标单元的两次连续写操作将会把第2次写操作的值写入目标单元,第1次写操作将没有意义
一.以下情况不能使用Cache与WriteBuffer
由于在ARM系统中,IO操作通常被映射为存储器操作,IO的输出操作可以通过存储器写入操作实现:IO的输入操作可以通过存储器读取操作实现,这样IO空间就被映射成了存储器空间。例如:ARM芯片,对USART,SPI接口的读写是通过映射存储器操作来实现的,当读SPI的数据时,是读特定寄存器地址,当写SPI数据时,是写特定的寄存器地址。由于前后两次读取同一地址的内容不相同,故对于ARM芯片的SPI,USART不能使用Cache。因而对于存储器映射的IO空间的操作就不能使用Cache技术。
由于写缓冲技术可能推迟写操作,它同样不适合对于存储器映射的IO空间的操作。例如:当CPU向中断控制器的IO端口写ACK,清除当前中断请求标志位,并重新使能中断,如果使用了写缓冲技术,CPU的写操作将被先写入高速的缓冲区,高速的缓冲区可能在以后某个时间再将结果写到IO端口,这样就造成一种假象,似乎外设又发出了中断请求。
由于上述原因,通常MMU允许将某些地址空间设置成uncacheable和unbufferable。MMU页表中地址转换条目的C和B位就是用于控制相应的存储空间的缓冲特性。其具体编码含义如下图所示:
程序设计中要注意以下几点:
1. 对于写回类型的Cache不能设置成Cached/Unbuffered.这是因为把它设置成Unbuffered是为了防止延迟存储访问操作的执行时间,而对于写回Cache,如果设置成Cached必然造成访问操作执行的延迟。
2. 对于存储器映射的IO空间要设置成Uncached/Unbuffered.原因已经在上面说了,如果在高级语言中访问存储器映射的IO空间时,还必须告诉编译器不要在优化时删掉有用的存储访问操作。在C语言中的作法是:使用关键字volatile声明存储器映射的IO空间来防止编译器在优化时删掉有用的存储访问。
3. 当程序的访问局部性很差时,应把存储区域设置成Uncached的。因为Cache引入的先提条件是建立在程序的时间局部性和空间局部性的。
二、存储系统的一致性问题
当存储系统中引入了Cache和写缓冲区时,同一地址单元的数据可能在系统中有多个副本,分别保存在cache中,写缓冲区中及主存中。如果系统采用了独立的数据cache和指令cache,同一地址单元的数据还有可能在数据cache和指令cache中有不同的版本。
当发生以下情况时,会产生不一致的情况:
1. 地址映射关系变化造成的数据不一致
情况1:Cache
在虚拟地址到物理地址映射发系发生变化前,如果虚拟地址A1所在的数据块已经预取在Cache中,当地址映射关系发生变化后,如果虚拟地址A1所在的物理地址发生了变化,这时当CPU访问A1时,再使用Cache中的数据块将会得到错误的结果。
解决方法:
在地址映射关系发生变化之前,执行下面操作:
如果数据Cache为写回类型的Cache,清空该数据Cache
使指令Cache中相应的块无效
如果数据Cache不是写回类型的Cache,则使数据Cache中相应的块无效
使指令Cache中相应的块无效
注意:为什么要分写回类型的Cache讨论,因为对于写回类型的Cache,无效并不使数据写回到主存中,必须用清空操作才行
情况2:WriteBuffer
当系统采用了写缓冲区时,在虚拟地址到物理地址映射关系发生变化前,如果CPU向虚拟地址A1的单元执行了写操作,该写操作已经将A1以及对应的数据写入到缓冲区中,当映射地址发生变化之后,如果虚拟地址A1所在的物理地址发生了变化,当写缓冲区将上面被延迟的写操作写到主存中时,使用的是变化后的物理地址,从而使写操作失败。
解决方法:
1. 将相关的存储区域设置成非缓冲的。
或者
2. 在地址映射变化之前,将写缓冲区被延迟的写操作全部执行,即清空写缓冲区。
注意:方法1是从整体上解决写缓冲区的问题。
2. 指令Cache的数据一致性问题
当系统中采用独立的数据Cache和指令Cache时,下面的情况会可能会造成指令不一致的情况。
情况:
a.读取地址为A1的指令,从而包含该指令的数据块被预取到Cache中。
b.与A1在同一个数据块的地址为A2的存储单元的数据被修改。这个写操作可能影响数据Cache中,写缓冲区中和地址为A2的存储单元的内容,但不影响指令Cache中A2的存储单元的内容。
c.如果A2存放的是指令,当该指令执行的时候,将会发生指令不一致的情况
解决方法:在a,b之间插入如下的操作序列
对于使用统一的数据Cache和指令Cache的系统,不需要任何操作
对于使用独立的数据Cache和指令Cache的系统,使指令Cache内容无效
如果数据Cache是写回类型的,清空数据Cache,使数据写回主存
指令数据不一致的问题,通常发生在以下情况:当可执行文件加载到主存之后,在程序跳转到入口点开始处执行之前,先执行上述操作序列,以保证以下面指令的是新加载的可执行代码,而不是原来的旧代码。
3. DMA造成的数据不一致问题
DMA操作会直接访问主存,而不会更新Cache和写缓冲中相应的内容,这样可能造成数据的不一致。
如果DMA从主存中读取的数据已经包含在Cache中,而且Cache中对应的数据已经被更新,这样DMA读到的将不是系统中最新的数据。同样,DMA写操作直接更新主存中的数据,如果该数据已经在Cache中,则Cache中的数据将会比主存中的数据“老”,也将造成数据的不一致。
解决方法:
在DMA读主存之前,清空数据Cache和清空写缓冲区
在DMA写主存之后,数据Cache中块使无效,或无效数据Cache
最根本的解决方法:
将DMA访问的存储区域设置成Uncahced/Unbuffered
2011-4-21