- UID
- 1029342
- 性别
- 男
|
/* bank4 DM9000 ,关闭cache和写缓冲,否则出现cache不一致问题 */
MMU_SetMTT(0x20000000,0x27f00000,0x20000000,RW_NCNB);
以上是DM9000裸机代码,其中关掉了DM9000的cache功能,下面给出原因:
volatile限定符,是可以防止编译器优化对设备寄存器的访问,但是对于有Cache的平台,仅仅这样还不够,还是无法防止Cache优化对设备寄存器的访问。在访问普通的内存单元时,Cache对程序员是透明的,比如执行了movzbl 0x804a019,%eax这样一条指令,我们并不知道eax的值是真的从内存地址0x804a019读到的,还是从Cache中读到的,如果Cache已经缓存了这个地址的数据就从Cache读,如果Cache没有缓存就从内存读,这些步骤都是硬件自动做的,而不是用指令控制Cache去做的,程序员写的指令中只有寄存器、内存地址,而没有Cache,程序员甚至不需要知道Cache的存在。同样道理,如果执行了mov %al,0x804a01a这样一条指令,我们并不知道寄存器的值是真的写回内存了,还是只写到了Cache中,以后再由Cache写回内存,即使只写到了Cache中而暂时没有写回内存,下次读0x804a01a这个地址时仍然可以从Cache中读到上次写的数据。然而,在读写设备寄存器时Cache的存在就不容忽视了,如果串口发送和接收寄存器的内存地址被Cache缓存了会有什么问题呢?如下图所示。
如果串口发送寄存器的地址被Cahce缓存,CPU执行单元对串口发送寄存器做写操作都写到Cache中去了,串口发送寄存器并没有及时得到数据,也就不能及时发送,CPU执行单元先后发出的1、2、3三个字节都会写到Cache中的同一个单元,最后Cache中只保存了第3个字节,如果这时 Cache把数据写回到串口发送寄存器,只能把第3个字节发送出去,前两个字节就丢失了。与此类似,如果串口接收寄存器的地址被Cache缓存,CPU执行单元在读第1个字节时,Cache会从串口接收寄存器读上来缓存,然而串口接收寄存器后面收到的2、3两个字节Cache并不知道,因为Cache把串口接收寄存器当作普通内存单元,并且相信内存单元中的数据是不会自己变的,以后每次读串口接收寄存器时,Cache都会把缓存的第1个字节提供给CPU执行单元。
如果把外设寄存器配置成Cache或写缓冲,那么通常会产生问题,所以最好将他们配置成不适用cache,并且不适用写缓冲,这就强制处理器在每次访问时都去读外设端口寄存器,而不是从cache中读取陈旧的信息
通常,有Cache的平台都有办法对某一段地址范围禁用Cache,一般是在页表中设置的,可以设定哪些页面允许Cache缓存,哪些页面不允许Cache缓存,MMU不仅要做地址转换和访问权限检查,也要和Cache协同工作。 |
|