VIPT PIPT VIVT 这几种Cache命中形式、Cache索引形式当然都是有非常多非常详细的解释,如果需要科普请直接在地址栏输入百度并回车。无非就是这仨大哥谁好谁不好,啥啥啥有缺陷,但在这里我要写的是一点其他的:好或不好其实都有用。
理解cache和MMU/SMMU是两位一体,硬件上当然是两个,功能也是两个,但从软件的角度来理解,这俩大哥不能分开。总的来说,Cache line只会有一个信号来决定是否hit,而Tag和Index则像是虎符的两半;而把Tag分给(S)MMU控制,(S)MMU就可以控制是否允许这笔对Cache line的访问。
VIVT
VIVT不用MMU参与,电路很简单,直接拿VA中的几个bit作为Index,另几个bit作为tag,找到指定Index后,一看Tag能命中,VA直接就Go到数据返回了。存在多个地址空间的时候,这么玩儿当然就废废了。但VIVT简单呀,很多时候,Cache不只是给CPU用,还有NPU、Codec、3D、GPGPU等等IP都会需要Cache,对于这些外设,工作的时候几乎不会切换地址空间,并且任务都是一个一个的小包包,打开一包干一次活儿。不光地址空间不切换,连地址映射都是CPU给提前喂,用VIVT省点晶体管,Cache做大点岂不很美?
VIPT
VIPT是硬件设计上所喜欢的,VI(VA中的几个bit)在访问Cache的时候是直接给出的,Cache拿到后可以去索引,在Cache干活的同时,VA还给到(S)MMU,说不定能直接命中出一个PA;等到Cache索引出对应的几个Cache Line的Tag的时候,MMU可能也命中出PT(PA中的几个bit)了;对着Tag一比,合上了就Go,合不上再走Miss路径。
应该来说,拿出PA这个事儿和索引出Cache Set真的是差不多时间的,像是Cache可能1Cycle就找到Set,但Cache一般是有多级的,有可能L1不命中,在L2的情况;像是ARM MMU的TLB好像也分两级,第一级命中可以1 Cycle直接出PA,第二级稍慢点儿。总之,硬件的同学们会尽量设计成同时命中哒。
PIPT
PIPT看起来除了慢核没啥用的,VA啥都做不了,只能等MMU出了PA才能查Cache;但实际上真的是这样吗?
我提一个问题:MMU做页表翻译这个动作的数据(也就是页表内容)访存是否经过cache呢?
MMU打出的访存也是可以使用cache的(不是全部哦),如果一个CPU上如果需要频繁切换进程,进而也就是需要频繁切换页表,甚至是虚拟化的情况下有两阶段页表都在切换,如果页表被Cache了,任务切换、VCPU切换之后的页表翻译都会加快,避免很多TLB凉的性能问题。
基于此,VIPT的时候MMU的访存如何命中Cache?
首先要有一个前提就是MMU的页表基地址寄存器总是要配置成PA的;(没有疑问吧)
也就是说,MMU翻译页表的时候,打出的访存地址一定是PA的;
既然是PA,那么MMU打出的访存就可以直接有了PT,那没VI怎么办?用PI?那岂不混淆了?
写到此处的时候小老弟嘿嘿一笑:其实这个问题只是个陷阱。
VI、PI是无所谓的,VI PI张三李四王五赵六都可以用来作为Cache Index,它只决定能用哪几行Cache Line,混用也没问题,Tag才是决定是否真的Hit。
结束
MMU动作在Cache之前,其实就是PIPT;MMU动作与Cache同时,那就是VIPT;MMU只在Cache决出Miss了才动,那就是VIVT。这么一看VI或是PI与MMU-cache的动作顺序是无关的,而VT或PT才是决定这个顺序的。