?
15.3??高速緩沖存儲(chǔ)器Cache
當(dāng)?shù)谝淮鶵ISC微處理器剛出現(xiàn)時(shí),標(biāo)準(zhǔn)存儲(chǔ)器元件的速度比當(dāng)時(shí)微處理器的速度快。很快,半導(dǎo)體工藝技術(shù)的進(jìn)展被用來(lái)提高微處理器的速度。標(biāo)準(zhǔn)DRAM部件雖然也快了一些,但其發(fā)展的主要精力則放在提高存儲(chǔ)容量上。
1980年,典型DRAM部件的容量為4KB。1981年和1982年開(kāi)發(fā)出了16KB芯片。這些部件的隨機(jī)訪問(wèn)速率為3MHz或4MHz,局部訪問(wèn)(頁(yè)模式)時(shí)速率大約快1倍。當(dāng)時(shí)的微處理器每秒需要訪問(wèn)存儲(chǔ)器2M次。
到2000年,DRAM部件每片的容量到達(dá)256Mbit,隨機(jī)訪問(wèn)速率在30MHz左右。微處理器每秒需要訪問(wèn)存儲(chǔ)器幾百兆次。如果處理器速率遠(yuǎn)高于存儲(chǔ)器,那么只能借助Cache才能滿足其全部性能。
Cache存儲(chǔ)器是一個(gè)容量小但存取速度非??斓拇鎯?chǔ)器,它保存最近用到的存儲(chǔ)器數(shù)據(jù)拷貝。對(duì)于程序員來(lái)說(shuō),Cache是透明的。它自動(dòng)決定保存哪些數(shù)據(jù)、覆蓋哪些數(shù)據(jù)?,F(xiàn)在Cache通常與處理器在同一芯片上實(shí)現(xiàn)。Cache能夠發(fā)揮作用是因?yàn)槌绦蚓哂芯植啃蕴匦?。所謂局部性就是指,在任何特定的時(shí)間,微處理器趨于對(duì)相同區(qū)域的數(shù)據(jù)(如堆棧)多次執(zhí)行相同的指令(如循環(huán))。
Cache經(jīng)常與寫緩存器(write?buffer)一起使用。寫緩存器是一個(gè)非常小的先進(jìn)先出(FIFO)存儲(chǔ)器,位于處理器核與主存之間。使用寫緩存的目的是,將處理器核和Cache從較慢的主存寫操作中解脫出來(lái)。當(dāng)CPU向主存儲(chǔ)器做寫入操作時(shí),它先將數(shù)據(jù)寫入到寫緩存區(qū)中,由于寫緩存器的速度很高,這種寫入操作的速度也將很高。寫緩存區(qū)在CPU空閑時(shí),以較低的速度將數(shù)據(jù)寫入到主存儲(chǔ)器中相應(yīng)的位置。
通過(guò)引入Cache和寫緩存區(qū),存儲(chǔ)系統(tǒng)的性能得到了很大的提高,但同時(shí)也帶來(lái)了一些問(wèn)題。比如,由于數(shù)據(jù)將存在于系統(tǒng)中的不同的物理位置,可能造成數(shù)據(jù)的不一致性;由于寫緩存區(qū)的優(yōu)化作用,可能有些寫操作的執(zhí)行順序不是用戶期望的順序,從而造成操作錯(cuò)誤。
15.3.1??Cache的分類
Cache有多種構(gòu)造方法。在最高層次,微處理器可以采用下面兩種組織中的一組。
(1)統(tǒng)一Cache。指令和數(shù)據(jù)用同一個(gè)Cache。結(jié)構(gòu)如圖15.8所示。
圖15.8??統(tǒng)一的指令Cache和數(shù)據(jù)Cache
(2)指令和數(shù)據(jù)分開(kāi)的Cache。有時(shí)這種組織方式也被稱為改進(jìn)的哈佛結(jié)構(gòu)。
圖15.9顯示了這種組織方式。
這兩種組織方式各有優(yōu)缺點(diǎn)。統(tǒng)一Cache能夠根據(jù)當(dāng)前程序的需要自動(dòng)調(diào)整指令在Cache存儲(chǔ)器的比例,比固定劃分的有更好的性能。另一方面,分開(kāi)的Cache使Load/Store指令能夠單周期執(zhí)行。
15.3.2??Cache性能的衡量
只有當(dāng)所需要的Cache存儲(chǔ)器內(nèi)容已經(jīng)在Cache時(shí),微處理器才能以高時(shí)鐘速率工作。因此,系統(tǒng)的總體性能就可以用存儲(chǔ)器訪問(wèn)中命中Cache的比例來(lái)衡量。當(dāng)要訪問(wèn)的內(nèi)容在Cache時(shí)稱為命中(hit),而要訪問(wèn)的內(nèi)容不在Cache時(shí)稱為未命中(miss)。在給定時(shí)間間隔內(nèi),Cache命中的次數(shù)與總的存儲(chǔ)器請(qǐng)求次數(shù)的比值被稱為命中率。
圖15.9??指令Cache和數(shù)據(jù)分開(kāi)的Cache
命中率用下面的公式進(jìn)行計(jì)算:
命中率=(Cache命中次數(shù)÷存儲(chǔ)器請(qǐng)求次數(shù))×100%
未命中率與命中率形式相似,即在給定時(shí)間間隔內(nèi),Cache未命中的總次數(shù)除以總的存儲(chǔ)器請(qǐng)求次數(shù)所得的百分比。未命中率與命中率之和等于100。
目前設(shè)計(jì)良好的處理器,Cache的未命中率只有百分之幾。未命中率依賴多個(gè)Cache參數(shù),包括Cache大小和組織。
?
15.3.3??Cache工作原理
Cache的基本存儲(chǔ)單元為Cache行(Cache?line)。存儲(chǔ)系統(tǒng)把Cache和主存儲(chǔ)器都劃分為相同大小的行。Cache與主存儲(chǔ)器交換數(shù)據(jù)是以行為基本單位進(jìn)行的。每一個(gè)Cache行都對(duì)應(yīng)于主存中的一個(gè)存儲(chǔ)塊(memory?block)。
Cache行的大小通常是2L字節(jié)。通常情況下是16字節(jié)(4個(gè)字)和32字節(jié)(8個(gè)字)。如果Cache行的大小為2L字節(jié),那么對(duì)主存的訪問(wèn)通常是2L字節(jié)對(duì)齊的。所以對(duì)于一個(gè)虛擬地址來(lái)說(shuō),它的bit[31∶L]位,是Cache行的一個(gè)標(biāo)識(shí)。當(dāng)CPU發(fā)出的虛擬地址的bit[31∶L]和Cache中的某行bit[31∶L]相同,那么Cache中包含CPU要訪問(wèn)的數(shù)據(jù),即成為一次Cache命中。
為了加快Cache訪問(wèn)的速度,又將多個(gè)Cache行劃分成一個(gè)Cache組(Cache?Set)。Cache組中包含的Cache行的個(gè)數(shù)通常也為2的N次方的倍數(shù)。為了方便起見(jiàn),取N=S。這樣,一個(gè)Cache組中就包含2S個(gè)Cache行。這時(shí),虛擬地址中的bit[L+S-1∶L]為Cache組的標(biāo)識(shí)。虛擬地址中余下的位bit[31∶L+S]成為一個(gè)Cache標(biāo)(Cache-tag)。它標(biāo)識(shí)了Cache行中的內(nèi)容和主存間的對(duì)應(yīng)關(guān)系。
圖15.10顯示了Cache的訪問(wèn)過(guò)程。
圖15.10??Cache訪問(wèn)過(guò)程
15.3.4??Cache與主存的關(guān)系
在Cache中采用地址映射將主存中的內(nèi)容映射到Cache地址空間。具體的說(shuō),就是把存放在主存中的程序按照某種規(guī)則裝入到Cache中,并建立主存地址到Cache地址之間的對(duì)應(yīng)關(guān)系。而地址變換是指當(dāng)程序已經(jīng)裝入到Cache后,在實(shí)際運(yùn)行過(guò)程中,把主存地址變換成Cache地址。
地址的映射和變換是密切相關(guān)的。采用什么樣的地址映射方法,就必然有與之對(duì)應(yīng)的地址變換。
常用的地址映射和變換方式包括直接映射和變換方式、組相聯(lián)映射和變換方式以及全相聯(lián)和變換方式。
(1)直接(direct-mapped)映射方式
直接映射是一種最簡(jiǎn)單,也是最直接的映射方式。主存中的每個(gè)地址都對(duì)應(yīng)Cache存儲(chǔ)器中惟一的一行。由于主存的容量遠(yuǎn)遠(yuǎn)大于Cache存儲(chǔ)器,所以在主存中很多地址被映射到同一個(gè)Cache行。
圖15.11顯示了主存與Cache的直接映射關(guān)系。
圖15.11??主存和Cache的直接映射
直接映射Cache是一種簡(jiǎn)單的解決方法,但這種設(shè)計(jì)使得每個(gè)主存塊在Cache中只有一個(gè)特定的行可以存放。如果程序同時(shí)用到對(duì)應(yīng)于Cache同一行的兩個(gè)主存塊,那么就會(huì)發(fā)生沖突,沖突的結(jié)果是導(dǎo)致Cache行的頻繁變換。這種由直接映射導(dǎo)致的Cache存儲(chǔ)器中的軟件沖突稱為顛簸(thrashing)問(wèn)題。
(2)組相聯(lián)映射方式
為了減少顛簸問(wèn)題,有些Cache使用了組相聯(lián)的映射策略。在組相聯(lián)的地址映射和變換中,把主存和Cache按同樣大小劃分成組(set),每個(gè)組都由相同的行數(shù)組成。
由于主存的容量比Cache容量大得多,因此,主存的組數(shù)要比Cache的組數(shù)多。從主存的組到Cache的組之間采用直接映射方式。主存中的一組與Cache中的一組之間建立了之間映射方式后,在兩個(gè)對(duì)應(yīng)的組內(nèi)部采用全相聯(lián)映射方式。
在ARM中采用的是組相聯(lián)的地址映射和變換方式。如果Cache的行大小為2L,則同一行中各地址的bit[31∶L]是相同的。如果Cache中組的大?。拷M中包含的行數(shù))為2S,則虛地址位bit[L+S∶L]用于選擇Cache中的某個(gè)組。
圖15.12顯示了一個(gè)Cache與主存儲(chǔ)器的組相聯(lián)映射
圖15.12??Cache與主存儲(chǔ)器組相聯(lián)映射
擁有相同組索引的Cache行稱為組相聯(lián)的(set?associative)。主存中的程序或代碼段可以在不影響程序執(zhí)行的情況下被分配到Cache中的某一組中。也就是說(shuō),將數(shù)據(jù)或代碼存入Cache行中的操作不會(huì)影響程序的執(zhí)行。
(3)全相聯(lián)映射方式
隨著Cache控制器的相聯(lián)度的提高,沖突的可能性減少了。理想的目標(biāo)是,盡量提高組相聯(lián)程度,使主存地址能夠映射到任意Cache行。這樣的Cache被稱為全相聯(lián)Cache。然而,隨著相聯(lián)度的提高,與之相匹配的硬件的復(fù)雜度也在提高。硬件設(shè)計(jì)者提高Cache相聯(lián)度的一種方法就是使用內(nèi)容尋址寄存器CAM(Content?Addressable?Memory)。
CAM使用一組比較器,以比較輸入的標(biāo)簽地址和存儲(chǔ)在每一個(gè)有效Cache行中的標(biāo)簽位。CAM采取了與RAM相反的工作方式;RAM在得到一個(gè)地址后再給出數(shù)據(jù);而CAM則是在檢測(cè)到給定的數(shù)據(jù)值在存儲(chǔ)器中后,再給出該數(shù)據(jù)的地址。使用CAM允許同時(shí)比較更多的地址中的標(biāo)簽位,從而增加了可以包含在一個(gè)組中的Cache行數(shù)。
在ARM920T和ARM940T存儲(chǔ)器核中,ARM使用了CAM來(lái)定位地址中的標(biāo)簽域。ARM920T和ARM940T中的Cache是64組組相聯(lián)的。圖15.13所示為ARM940T的Cache結(jié)構(gòu)圖。Cache控制器把地址標(biāo)簽域作為CAM的輸入,它的輸出選擇了包含有效Cache行的組。
圖15.13??ARM940T64路組相聯(lián)Cache
訪問(wèn)地址的標(biāo)簽部分被作為4個(gè)CAM的輸入,輸入標(biāo)簽的同時(shí)與存儲(chǔ)在64組中的所有Cache標(biāo)簽比較。如果有一個(gè)匹配,那么數(shù)據(jù)就由Cache寄存器提供;如果沒(méi)有匹配,存儲(chǔ)器就會(huì)產(chǎn)生一個(gè)失效(misss)信號(hào)。
控制器使用組索引位(set?index)在4個(gè)CAM中選擇一個(gè)。被選中的CAM會(huì)在Cache存儲(chǔ)器中選擇一個(gè)Cache行,該地址的數(shù)據(jù)索引部分(data?index)在該Cache行中選擇出所需的字、半字或者字節(jié)。
15.3.5??Cache的寫策略
當(dāng)CPU更新了Cache內(nèi)容時(shí),要將結(jié)果寫回到主存中,通常有兩種方法:
·??直寫法(write-through);
·??回寫法(write-back)。
直寫法是指,當(dāng)CPU在執(zhí)行寫操作時(shí),必須把數(shù)據(jù)同時(shí)寫入Cache和主存,以確保Cache和主存數(shù)據(jù)一致。在這種寫策略下,處理器在每次寫Cache時(shí)也要寫相應(yīng)的主存單元。由于要訪問(wèn)主存,直寫法的速度比回寫法要慢一些。
回寫法是指,當(dāng)處理器和寫Cache命中時(shí),只向Cache存儲(chǔ)器寫數(shù)據(jù),而不立即寫入主存。這樣,主存儲(chǔ)器與相應(yīng)的Cache行數(shù)據(jù)有可能不一致。Cache中的數(shù)據(jù)是新的,而主存中的數(shù)據(jù)可能是較早的、沒(méi)有被更新過(guò)的。
配置成回寫法的Cache要使用Cache行的狀態(tài)信息塊中的一個(gè)或多個(gè)臟位(dirty?bit)。當(dāng)回寫Cache控制器向Cache存儲(chǔ)器中的某一行寫入數(shù)據(jù)時(shí),它會(huì)將臟位設(shè)置為1。如果控制器內(nèi)核此后訪問(wèn)該Cache行,那么通過(guò)臟位的狀態(tài)就可以知道該Cache行中含有主存儲(chǔ)器中沒(méi)有的數(shù)據(jù)。如果Cache控制器要將一個(gè)臟位被設(shè)置的Cache行替換出Cache存儲(chǔ)器,那么該Cache行數(shù)據(jù)會(huì)自動(dòng)被寫入主存單元中??刂破魍ㄟ^(guò)這種方法來(lái)防止只存在于Cache中而主存中沒(méi)有的重要信息的丟失。
表15.12比較了直寫法和回寫法的優(yōu)缺點(diǎn)。
表15.12 直寫法與回寫法
寫??策??略 |
直??寫??法 |
回??寫??法 |
可靠性 |
高 |
低 |
與主存的通信量 |
多 |
少 |
控制的復(fù)雜性 |
簡(jiǎn)單 |
復(fù)雜 |
硬件實(shí)現(xiàn)代價(jià) |
大 |
小 |
下面分析產(chǎn)生這些性能差異的原因。
·??可靠性。直寫法要優(yōu)于回寫法。這是因?yàn)橹睂懛ㄊ冀K保證Cache是主存的正確副本。當(dāng)Cache發(fā)生錯(cuò)誤時(shí),可以從主存中糾正。
·??與主存的通信量。一般情況下,回寫法少于直寫法。這是因?yàn)椋环矫?,Cache的命中率很高,對(duì)于回寫法來(lái)說(shuō),CPU絕大多數(shù)操作只需要寫Cache,不必寫主存。另一方面,當(dāng)Cache失效時(shí),要將Cache中的行替換到主存,而直寫法每次只寫一個(gè)字到主存。總的來(lái)說(shuō),由于直寫法在每次寫Cache時(shí),同時(shí)寫主存,從而增加了寫操作的開(kāi)銷。而回寫法是把與主存的數(shù)據(jù)交換集中到一次主存操作,可能要一次性的進(jìn)行多個(gè)字的操作。
·??控制的復(fù)雜性。直寫法必回寫法簡(jiǎn)單。直寫法在Cache的行狀態(tài)表中不需要修改位。同時(shí),直寫法的糾錯(cuò)技術(shù)相對(duì)簡(jiǎn)單。
·??硬件代價(jià)?;貙懛ū戎睂懛ê谩R?yàn)橹睂懛ㄖ?,每次寫操作都要寫主存,因此為了?jié)省寫主存所花費(fèi)的時(shí)間,通常要采用一個(gè)高速小容量的緩存存儲(chǔ)器,把要寫的數(shù)據(jù)和地址寫到這個(gè)緩存中。在每次讀主存時(shí),也要首先判斷所讀的數(shù)據(jù)是否在這個(gè)緩存中。而回寫法不需要上述操作,相對(duì)硬件代價(jià)要小。
?
15.3.6??Cache的替換策略
在Cache訪問(wèn)過(guò)程中,發(fā)現(xiàn)查找的Cache行已經(jīng)失效,則需要從主存中調(diào)入新的行到Cache中。在采用組相聯(lián)的Cache中,一個(gè)來(lái)自主存的行可以放入多個(gè)Cache組中。當(dāng)所有組中的對(duì)應(yīng)行都已經(jīng)裝滿時(shí),就要使用Cache替換算法,從這些組中找出一個(gè)Cache,把它調(diào)回到主存中原來(lái)存放它的地方,騰出新行來(lái)存放新調(diào)入的行。被選中替換的Cache行被稱為丟棄者(victim)。如果丟棄者中包含有效的臟數(shù)據(jù),那么在該行被寫入新數(shù)據(jù)之前,控制器必須把該行中的數(shù)據(jù)寫到主存。選擇和替換丟棄Cache行的過(guò)程被稱為淘汰(eviction)。
Cache控制器選擇下一個(gè)丟棄Cache行的策略被稱為替換策略。在ARM常用的替換算法有兩種:輪轉(zhuǎn)算法和隨機(jī)替換算法。
輪轉(zhuǎn)算法又叫循環(huán)法,這種算法維護(hù)一個(gè)邏輯計(jì)數(shù)器,每進(jìn)行一次替換,計(jì)算器加1,當(dāng)計(jì)算器達(dá)到最大值時(shí),就被復(fù)位成預(yù)先定義好的一個(gè)基值。這種算法容易預(yù)測(cè)最壞情況下的Cache性能。但它一個(gè)明顯缺點(diǎn)就是,在程序發(fā)生很小變化時(shí),可能造成Cache性能急劇下降。
隨機(jī)算法從特定的位置上隨機(jī)地選出一行替換出去。它通過(guò)一個(gè)隨機(jī)發(fā)生器來(lái)完成上述操作。當(dāng)每次需要替換Cache行時(shí),隨機(jī)發(fā)生器將產(chǎn)生一個(gè)隨機(jī)數(shù),用新行將編號(hào)為該隨機(jī)數(shù)的行替換出去。這種算法與輪轉(zhuǎn)算法最大的區(qū)別在于它在每次產(chǎn)生替換行時(shí),增加的是一個(gè)非連續(xù)值,這個(gè)值是由控制器隨機(jī)產(chǎn)生的。同樣,當(dāng)丟棄計(jì)算器達(dá)到最大值時(shí),會(huì)被復(fù)位成預(yù)先定義好的一個(gè)基值。
相比之下,隨機(jī)算法沒(méi)有考慮到程序的局部性特點(diǎn),因而效果有時(shí)不盡人意,同時(shí)這種算法不易預(yù)測(cè)最壞情況下Cache性能。而輪轉(zhuǎn)法就有更好的可預(yù)測(cè)性,容易預(yù)測(cè)最壞情況下Cache性能,在一些實(shí)時(shí)系統(tǒng)中,十分重視這一點(diǎn)。但是,輪轉(zhuǎn)法替換策略在存儲(chǔ)器訪問(wèn)發(fā)生很小變化時(shí),可能造成Cache性能有較大變化。
表15.13顯示了目前比較流行的ARM核所使用的策略。
表15.13 常見(jiàn)ARM核使用的替換策略
內(nèi)????核 |
寫??策??略 |
替?換?策?略 |
ARM720T |
直寫法 |
隨機(jī) |
ARM740T |
直寫法 |
隨機(jī) |
ARM920T |
直寫法、回寫法 |
隨機(jī)、輪轉(zhuǎn) |
ARM940T |
直寫法、回寫法 |
隨機(jī) |
ARM926EJ-S |
直寫法、回寫法 |
隨機(jī)、輪轉(zhuǎn) |
ARM946E |
直寫法、回寫法 |
隨機(jī)、輪轉(zhuǎn) |
ARM1020E |
直寫法、回寫法 |
隨機(jī)、輪轉(zhuǎn) |
ARM1026EJS |
直寫法、回寫法 |
隨機(jī)、輪轉(zhuǎn) |
Intel?Strong?ARM |
回寫法 |
輪轉(zhuǎn) |
Intel?Xscale |
直寫法 |
輪轉(zhuǎn) |
?
15.3.7??與Cache相關(guān)的編程接口
與Cache編程相關(guān)的CP15的寄存器共有3個(gè),它們分別為c1、c7及c9。
(1)寄存器c1中與Cache相關(guān)的位
c1寄存器在前面CP15寄存器一節(jié)中已經(jīng)介紹過(guò),下面對(duì)Cache的控制位進(jìn)行詳細(xì)介紹。
表15.14顯示了c1中與Cache有關(guān)位的作用。
表15.14 c1中與Cache相關(guān)的位
相??關(guān)??位 |
作????用 |
C(bit[2]) |
當(dāng)數(shù)據(jù)Cache和指令Cache分開(kāi)時(shí),本控制位禁止/使能數(shù)據(jù)Cache 當(dāng)數(shù)據(jù)Cache和指令Cache統(tǒng)一時(shí),本控制位禁止/使能整個(gè)Cache 0:禁止Cache 1:使能Cache 如果系統(tǒng)中不含Cache,讀取時(shí)該位返回0,寫入時(shí)忽略該位 當(dāng)系統(tǒng)中Cache不能禁止時(shí),讀取返回1,寫入時(shí)忽略該位 |
續(xù)表
相??關(guān)??位 |
作????用 |
I(bit[12]) |
當(dāng)數(shù)據(jù)Cache和指令Cache是分開(kāi)的,本控制位禁止/使能指令Cache 0:禁止指令Cache 1:使能指令Cache 如果系統(tǒng)中使用統(tǒng)一的指令Cache和數(shù)據(jù)Cache或者系統(tǒng)中不含Cache,讀取該位時(shí)返回0,寫入時(shí)忽略該位 當(dāng)系統(tǒng)中的指令Cache不能禁止時(shí),讀取該位返回1,寫入時(shí)忽略該位 |
RR(bit[14]) |
如果系統(tǒng)中Cache的淘汰算法可以選擇的話,本控制位選擇淘汰算法 0:選擇常規(guī)的淘汰算法,如隨機(jī)淘汰算法 1:選擇預(yù)測(cè)性的淘汰算法,如輪轉(zhuǎn)(round-robin)淘汰算法 如果系統(tǒng)中淘汰算法不可選擇,寫入該位時(shí)被忽略,讀取該位時(shí),根據(jù)其淘汰算法可以簡(jiǎn)單地預(yù)測(cè)最壞情況,并返回1或者0 |
?
(2)寄存器c7
CP15中的寄存器c7主要用于控制Cache和寫緩存。
注意 |
c7有時(shí)也用于其他相似的功能,如果系統(tǒng)中存在預(yù)測(cè)緩存(prefetch?buffers)和分支目標(biāo)(branch?target)Cache,c7也將負(fù)責(zé)對(duì)它們進(jìn)行控制。 |
c7是一個(gè)只寫存儲(chǔ)器,可以使用協(xié)處理器指令MCR對(duì)其進(jìn)行操作。如果程序中包含讀c7的操作,那么指令的結(jié)果不可預(yù)知。
使用MCR指令寫該寄存器的命令格式如下所示。
MCR??P15,0,<Rd>,<c7>,<CRm>,<opcode2>
其中,CRm和opcode2的不同組合,決定指令執(zhí)行的不同操作。具體組合與操作的對(duì)應(yīng)關(guān)系見(jiàn)表15.15。
表15.15 CRm與opcode2不同組合與操作的應(yīng)用關(guān)系
CRm |
Opcode2 |
含????義 |
數(shù)????據(jù) |
c0 |
4 |
等待中斷 |
0(SBZ,should?be?zero) |
c5 |
0 |
使整個(gè)指令Cache無(wú)效 |
0 |
c5 |
1 |
使指令Cache中某行無(wú)效 |
虛擬地址 |
c5 |
2 |
使指令Cache中某行無(wú)效 |
組號(hào)/索引 |
c5 |
4 |
清空預(yù)取緩存區(qū) |
0 |
c5 |
6 |
清空整個(gè)分支目標(biāo)Cache |
0 |
c5 |
7 |
清空分支目標(biāo)Cache中的某入口項(xiàng) |
生產(chǎn)商定義 |
c6 |
0 |
使整個(gè)數(shù)據(jù)Cache無(wú)效 |
0 |
續(xù)表
CRm |
Opcode2 |
含????義 |
數(shù)????據(jù) |
c6 |
1 |
使數(shù)據(jù)Cache中的某行無(wú)效 |
虛擬地址 |
c6 |
2 |
使數(shù)據(jù)Cache中的某行無(wú)效 |
組號(hào)/索引 |
c7 |
0 |
使整個(gè)統(tǒng)一Cache無(wú)效 哈佛結(jié)構(gòu)中,使整個(gè)數(shù)據(jù)Cache和指令Cache無(wú)效 |
0 |
c7 |
1 |
使統(tǒng)一Cache中某行無(wú)效 |
虛擬地址 |
c7 |
2 |
使統(tǒng)一Cache中某行無(wú)效 |
組號(hào)/索引 |
c8 |
2 |
等待中斷 |
0 |
c10 |
1 |
清理數(shù)據(jù)Cache行 |
虛擬地址 |
c10 |
2 |
清理數(shù)據(jù)Cache行 |
組號(hào)/索引 |
c10 |
4 |
清除寫緩存區(qū) |
0 |
c11 |
1 |
清理統(tǒng)一Cache行 |
虛擬地址 |
c11 |
2 |
清理統(tǒng)一Cache行 |
組號(hào)/索引 |
c13 |
1 |
預(yù)取指令Cache中的某行 |
虛擬地址 |
c14 |
1 |
清理并使數(shù)據(jù)Cache中的某行無(wú)效 |
虛擬地址 |
c14 |
2 |
清理并使數(shù)據(jù)Cache中的某行無(wú)效 |
組號(hào)/索引 |
c15 |
1 |
清理并使統(tǒng)一Cache中的某行無(wú)效 |
虛擬地址 |
c15 |
2 |
清理并使統(tǒng)一Cache中的某行無(wú)效 |
組號(hào)/索引 |
(3)寄存器c9
將Cache進(jìn)入存儲(chǔ)系統(tǒng)的注意目的是要提高系統(tǒng)的平均訪問(wèn)速度。但Cache是一把雙刃劍,在某些情況下,可能使系統(tǒng)的性能更遭。下面列出了3種使Cache性能明顯下降的原因。
①?Cache訪問(wèn)未命中,處理器轉(zhuǎn)向主存尋址數(shù)據(jù),這期間的延時(shí)對(duì)系統(tǒng)性能影響很大。
②?在回寫型Cache中,如果Cache中的數(shù)據(jù)所在地址被存儲(chǔ)管理單元重新定位(即Cache中存儲(chǔ)的為虛地址數(shù)據(jù)),那么數(shù)據(jù)回寫的操作延時(shí)很大。
③?當(dāng)處理器需要一個(gè)字節(jié)數(shù)據(jù),而此數(shù)據(jù)恰好不在Cache中,那么Cache的替換策略就會(huì)將整個(gè)Cache行換進(jìn),增加了系統(tǒng)不必要的開(kāi)銷。
?
以上3點(diǎn)對(duì)實(shí)時(shí)系統(tǒng)來(lái)說(shuō),影響更為明顯。
為了減少這種不利的影響,在ARM系統(tǒng)中引入了Cache內(nèi)容鎖定技術(shù)。這種技術(shù)允許編程人員人為地將一些關(guān)鍵代碼或數(shù)據(jù)預(yù)取到Cache中后,通過(guò)寄存器操作對(duì)其設(shè)定一定的屬性,這樣當(dāng)有Cache未命中發(fā)生,需要進(jìn)行Cache替換時(shí),將這些數(shù)據(jù)保護(hù)起來(lái),使這些關(guān)鍵代碼或數(shù)據(jù)不會(huì)被換出。
這種策略在很大程度上保證了處理器對(duì)關(guān)鍵代碼或數(shù)據(jù)訪問(wèn)時(shí)的性能。
Cache的鎖定操作是分組塊(block)為單位進(jìn)行的,它的分塊方法如下。
為了敘述方便,作下述假設(shè)。
L(Length?of?the?Line):Cache的基本存儲(chǔ)單元行的大小。
A(Associativity):表示每個(gè)Cache組中的行數(shù)。
N(Number?of?Sets):Cache中的組數(shù)。
M表示Cache中的鎖定塊。
每個(gè)鎖定塊(lockdown?block)包括Cache每組中的一行。這樣Cache中共有A個(gè)鎖定塊,其編號(hào)為從0到A-1。其中編號(hào)為0的鎖定塊中包含Cache組0中的0#行,組1中的0#行,直到組A-1中的0#行。依此類推,鎖定塊1包含Cache組0中的1#行,組1中的1#行,直到組A-1中的1#行。這樣每個(gè)鎖定塊中包含了N個(gè)Cache行。
當(dāng)編號(hào)為0~M的鎖定塊被鎖定在Cache中,編號(hào)為M+1~A的鎖定塊可以用于正常的Cache替換操作。
注意 |
編程中不能將全部Cache鎖定,至少要留出一個(gè)未鎖定的塊來(lái)支持存儲(chǔ)器的正常操作。 |
每一個(gè)鎖定塊都包含有N個(gè)不同組中的Cache行。建議程序在使用Cache鎖定時(shí),使每個(gè)Cache塊中的N個(gè)Cache行映射的為存儲(chǔ)器中的連續(xù)地址。也就是說(shuō),存儲(chǔ)器中N×L大小的聯(lián)系區(qū)域被映射到Cache中鎖定,這塊區(qū)域是Cache行邊界對(duì)齊的(如果一個(gè)Cache行包含4字節(jié),那么被鎖定的區(qū)域要是4字節(jié)對(duì)齊的,如果一個(gè)Cache行包含8字節(jié),那么被鎖定的Cache行就是8字節(jié)對(duì)齊的)。
在ARM的存儲(chǔ)管理體系中,主要依靠系統(tǒng)協(xié)處理器和協(xié)處理器的寄存器c9來(lái)實(shí)現(xiàn)和管理Cache鎖定。如果系統(tǒng)中使用的是數(shù)據(jù)和指令分離的Cache,那么就依靠協(xié)處理器指令MCR和MRC中的<opcode>2來(lái)區(qū)分:
·??<opcode>=0使用數(shù)據(jù)Cache鎖定寄存器;
·??<opcode>=1使用指令Cache鎖定寄存器。
如果系統(tǒng)使用的是數(shù)據(jù)和指令統(tǒng)一的Cache,那么<opcode2>要設(shè)置成0。
另外,無(wú)論是MCR指令還是MCR指令,指令中的<CRm>通常設(shè)為c0。
寄存器c9有兩種主要的格式:格式A和格式B。
格式A的編碼如圖15.14所示。
圖15.14??格式A編碼
?
程序員通過(guò)指令對(duì)寄存器中的Cache組內(nèi)行號(hào)進(jìn)行操作。讀取格式A的寄存器c9,將返回最后一次寫入寄存器c9的值。將數(shù)據(jù)index寫入寄存器c9,就是對(duì)要鎖定的Cache行進(jìn)行設(shè)置。當(dāng)用MCR指令向寄存器寫入數(shù)據(jù)時(shí),執(zhí)行以下操作。
①?當(dāng)下一次發(fā)生Cache未命中時(shí),將預(yù)取的存儲(chǔ)器行存入Cache中與該行相對(duì)應(yīng)的組中編號(hào)為index的Cache行中。
②?這時(shí)被鎖定的Cache塊包括序號(hào)為0~index-1的鎖定塊。當(dāng)發(fā)生Cache替換時(shí),從編號(hào)為index到A-1的塊中選擇被替換的塊。
格式B的編碼如圖15.15所示。
程序員通過(guò)指令對(duì)寄存器中的Cache組內(nèi)行號(hào)進(jìn)行操作。讀取格式B的寄存器c9,將返回最后一次寫入寄存器c9的值。將數(shù)據(jù)index寫入寄存器c9,就是對(duì)要鎖定的Cache行進(jìn)行設(shè)置。當(dāng)用MCR指令向寄存器寫入數(shù)據(jù)時(shí),執(zhí)行以下操作。
圖15.15??格式B編碼
①?當(dāng)L=0時(shí),如果方式Cache未命中,將預(yù)取的存儲(chǔ)行存入Cache中與該行對(duì)應(yīng)的組中序號(hào)為index的Cache行中。
②?當(dāng)L=1時(shí),如果本次寫操作之前L=0,并且index值小于本次寫入的index,本次寫操作執(zhí)行的結(jié)果不可預(yù)知;否則,這時(shí)被鎖定的Cache塊包括序號(hào)為0~index-1的塊。當(dāng)發(fā)生Cache替換時(shí),從序號(hào)為index~A-1的塊中選擇被替換的塊。
下面以鎖定塊N來(lái)說(shuō)明要鎖定一個(gè)Cache塊的步驟。
①?首先確保在下面的整個(gè)Cache鎖定過(guò)程不會(huì)被中斷打斷。如果程序要求中斷不能關(guān)閉,那么必須確保被打開(kāi)的中斷相關(guān)代碼和數(shù)據(jù)位于非緩存(uncachable)的存儲(chǔ)區(qū)域。
關(guān)中斷的典型做法如下所示。
MRS??r2,CPSR????????????????????????;讀出當(dāng)前程序狀態(tài)字?CPSR
ORR??r2,r2,#?0x000000C0???????????;關(guān)中斷
MSR??CPSR_cxsf,r2??????????????????;設(shè)置當(dāng)前程序狀態(tài)字
②?如果鎖定是指令Cache或者統(tǒng)一Cache,必須保證鎖定過(guò)程所執(zhí)行的代碼位于非緩存的存儲(chǔ)域。
③?如果鎖定的是數(shù)據(jù)Cache或者統(tǒng)一的Cache,必須保證鎖定過(guò)程所執(zhí)行的數(shù)據(jù)位于非緩存的存儲(chǔ)域。
④?保證要鎖定的代碼和數(shù)據(jù)位于緩存的存儲(chǔ)區(qū)域中。
⑤?如果要鎖定的代碼和數(shù)據(jù)不在Cache中,使用Cache清除或清理指令,將其置換到Cache中。
⑥?N次循環(huán)執(zhí)行下面的操作。
·??index=I寫入寄存器c9,當(dāng)使用B格式的鎖定寄存器時(shí),令L=0。
·??如果鎖定的是數(shù)據(jù)Cache或數(shù)據(jù)和指令統(tǒng)一Cache,使用LDR指令將數(shù)據(jù)從內(nèi)存讀出,這個(gè)讀操作將使要鎖定的內(nèi)容存在于Cache行中。
·??如果鎖定的是指令Cache,那么要借助c7寄存器,相關(guān)指令詳細(xì)內(nèi)容,參見(jiàn)c7寄存器一節(jié)。
⑦??將index=N寫入寄存器c9,當(dāng)使用B格式的鎖定寄存器時(shí),令L=0。
如果要解除對(duì)N鎖定塊的鎖定,執(zhí)行以下操作。
·??將index=0寫入寄存器c9。
·??當(dāng)使用格式B的鎖定寄存器時(shí),令L=0。
15.3.8??內(nèi)存一致性
當(dāng)一個(gè)系統(tǒng)中同時(shí)使用了Cache、寫緩存時(shí),同一地址的數(shù)據(jù)可能同時(shí)出現(xiàn)在包括系統(tǒng)內(nèi)存在內(nèi)的多個(gè)不同的物理位置中。如果Cache引入了哈佛架構(gòu),使用數(shù)據(jù)和指令分類的Cache,那情況將更復(fù)雜。
由于上述存儲(chǔ)系統(tǒng)的多樣性特點(diǎn),當(dāng)從內(nèi)存中讀取數(shù)據(jù)時(shí),不能保證讀取的是數(shù)據(jù)的最新值(即有可能出現(xiàn)下述情況:寫操作將數(shù)據(jù)寫入到Cache中,但更新數(shù)據(jù)還沒(méi)有被回寫到內(nèi)存)。
ARM存儲(chǔ)系統(tǒng)中,數(shù)據(jù)不一致問(wèn)題一方面可以通過(guò)存儲(chǔ)系統(tǒng)自動(dòng)保證解決,另一方面編寫程序時(shí)要遵循一定的規(guī)則,防止數(shù)據(jù)不一致性發(fā)生。
下面就幾個(gè)常出現(xiàn)數(shù)據(jù)不一致的地方進(jìn)行討論。
·??地址映射發(fā)生變化時(shí)
·??指令和數(shù)據(jù)分離的Cache
·??系統(tǒng)執(zhí)行DMA(Direct?Memory?Access)操作
(1)地址映射發(fā)生的變換
當(dāng)系統(tǒng)中使用MMU時(shí),Cache行對(duì)應(yīng)的地址可能是:
①?內(nèi)存中的實(shí)際地址;
②?經(jīng)過(guò)地址轉(zhuǎn)換后的虛擬地址。
如果查詢Cache時(shí)相聯(lián)地址比較使用的是虛擬地址,則當(dāng)系統(tǒng)地址到物理地址的映射發(fā)生變換時(shí),可能造成Cache中數(shù)據(jù)與主存中的不一致。
同時(shí),當(dāng)系統(tǒng)中使用了寫緩存,處理器對(duì)寫緩存中的數(shù)據(jù)處理也是按虛擬地址進(jìn)行的,所以同樣會(huì)發(fā)生數(shù)據(jù)不統(tǒng)一的問(wèn)題。比如,當(dāng)前處理器使用虛擬地址向某個(gè)內(nèi)存單元寫數(shù)據(jù),該寫操作已經(jīng)將虛擬地址和數(shù)據(jù)寫入到寫緩存區(qū)中,此時(shí),虛擬地址到物理地址的映射關(guān)系發(fā)生變換,使先前要寫入數(shù)據(jù)的虛擬地址發(fā)生了變化,當(dāng)寫緩存將上面被延時(shí)的寫操作寫到主存時(shí),使用的是變換后的地址,從而寫操作執(zhí)行失敗。
為了避免發(fā)生這種數(shù)據(jù)不統(tǒng)一的情況,在系統(tǒng)虛擬地址到物理地址的映射關(guān)系發(fā)生變換前,根據(jù)系統(tǒng)的具體情況,執(zhí)行下面的操作序列中的一種或幾種。
·??如果數(shù)據(jù)Cache為寫回型Cache,清空該數(shù)據(jù)Cache。
·??使數(shù)據(jù)Cache中相應(yīng)的行無(wú)效。
·??使指令Cache中相應(yīng)的行無(wú)效。
·??將寫緩存區(qū)中被延時(shí)的操作全部執(zhí)行。
·??有些情況可能還要求相關(guān)的存儲(chǔ)區(qū)域被置換成非緩存的。
?
(2)指令Cache
當(dāng)系統(tǒng)中采用分離的數(shù)據(jù)Cache和指令Cache時(shí),下面的幾種情況可能造成指令不一致情況的發(fā)生。
①?地址為A1的指令被預(yù)取,該指令的數(shù)據(jù)行被取到Cache中。
②?和A1同在一個(gè)數(shù)據(jù)行的地址為A2的數(shù)據(jù)被一條存儲(chǔ)器寫操作修改。這個(gè)數(shù)據(jù)寫操作可能影響數(shù)據(jù)Cache中、寫緩存中和主存的地址為A2的存儲(chǔ)單元內(nèi)容,但不影響指令Cache中地址為A2的存儲(chǔ)單元中的內(nèi)容。
③?如果地址A2存放的是指令,當(dāng)該指令執(zhí)行時(shí),就可能發(fā)生指令不一致問(wèn)題。如果地址A2所在的行還在指令Cache中,系統(tǒng)將執(zhí)行修改前的指令;如果地址A2所在的行不在指令Cache中,地址將執(zhí)行修改后的指令。
為了避免這種指令不一致的情況發(fā)生,要在地址A2的數(shù)據(jù)被修改前執(zhí)行一些防護(hù)性的操作。也就是說(shuō),在步驟①和②之間插入下面必要的操作。
·??如果系統(tǒng)中使用的數(shù)據(jù)、指令統(tǒng)一的Cache,程序跳到步驟②繼續(xù)執(zhí)行。
·??對(duì)于使用數(shù)據(jù)和指令分離Cache的系統(tǒng),使指令Cache的內(nèi)容無(wú)效。
·??對(duì)于使用數(shù)據(jù)和指令分離Cache的系統(tǒng),如果數(shù)據(jù)Cache是寫回類型的,清空數(shù)據(jù)Cache。
上述操作系列可作為一種標(biāo)準(zhǔn),應(yīng)用于一些典型的場(chǎng)合。
注意 |
當(dāng)可執(zhí)行文件加載到主存中后,在程序跳轉(zhuǎn)到入口點(diǎn)處開(kāi)始執(zhí)行之前,先執(zhí)行上述操作序列,以保證新加載的可執(zhí)行代碼正確執(zhí)行。 |
(3)DMA造成的數(shù)據(jù)不一致
DMA操作直接訪問(wèn)內(nèi)存,不更新Cache和寫緩存區(qū)中相應(yīng)內(nèi)容,這樣就很可能造成數(shù)據(jù)不一致。
為了避免DMA造成的數(shù)據(jù)不統(tǒng)一,根據(jù)系統(tǒng)情況,執(zhí)行下面操作的一種和幾種。
·??將DMA訪問(wèn)的存儲(chǔ)器設(shè)置成非緩存的
·??將DMA訪問(wèn)的存儲(chǔ)區(qū)所涉及的數(shù)據(jù)Cache中的行設(shè)置成無(wú)效,或者清空數(shù)據(jù)Cache。
·??清空寫緩存區(qū)(將寫緩存區(qū)中延時(shí)操作全部執(zhí)行)。
·??在DMA訪問(wèn)期間限制存儲(chǔ)器訪問(wèn)DMA所訪問(wèn)的存儲(chǔ)區(qū)域。
15.3.9??Cache初始化子程序示例
下面給出了一段例子代碼,此代碼以ARM740T芯片為參考,顯示了Cache初始化的標(biāo)準(zhǔn)過(guò)程。
;下面代碼必須運(yùn)行于處理器的特權(quán)模式下。
????????AREA???INIT740,?CODE,?READONLY ;設(shè)置段屬性
????????ENTRY
????????EXPORT?Cache_Init ;以便作為子程序被其他程序使用
Cache_Init
;禁止MMU/MPU
;清理數(shù)據(jù)Cache
;
;
???????MRC?????p15,?0,?r0,?c1,?c0,?0 ;讀CP15寄存器c1到r0
???????BIC?????r0,?r0,?#0x1 ;清除bit[0]?
???????MCR?????p15,?0,?r0,?c1,?c0,?0 ;將設(shè)置的新值寫回
???????MOV?????r0,#0 ;準(zhǔn)備禁止其他域
???????MCR?????p15,?0,?r0,?c6,?c1,?0
???????MCR?????p15,?0,?r0,?c6,?c2,?0
???????MCR?????p15,?0,?r0,?c6,?c3,?0
???????MCR?????p15,?0,?r0,?c6,?c4,?0
;???????MCR?????p15,?0,?r0,?c6,?c5,?0
;???????MCR?????p15,?0,?r0,?c6,?c6,?0
;???????MCR?????p15,?0,?r0,?c6,?c7,?0??
;
;?區(qū)域0:背景區(qū):從0x0地址開(kāi)始的4GB存儲(chǔ)空間
;?區(qū)域1:SRAM區(qū):從0x0地址開(kāi)始的0x4000字節(jié)存儲(chǔ)空間
;?區(qū)域2:FLASH:從0x24000000開(kāi)始的0x02000000字節(jié)存儲(chǔ)空間
;?區(qū)域3:外設(shè)區(qū):從0x10000000地址開(kāi)始的0x10000000字節(jié)存儲(chǔ)空間
;開(kāi)啟?region?0?
?????????MOV?????r0,#2_111111
?????????MCR?????p15,?0,?r0,?c6,?c0,?0 ;?region?0區(qū)域0
;?開(kāi)啟region?1
?????????MOV?????r0,#2_100011
?????????MCR?????p15,?0,?r0,?c6,?c1,?0 ;?region?1區(qū)域1
;?開(kāi)啟region?2
?????????LDR?????r0,=2_110001+0x24000000
?????????MCR?????p15,?0,?r0,?c6,?c2,?0 ;?region?2區(qū)域2
;?開(kāi)啟region?3
?????????LDR?????r0,=2_110111?+?0x10000000
?????????MCR?????p15,?0,?r0,?c6,?c3,?0 ;?region?3區(qū)域3
;?開(kāi)啟Cache/寫緩存?
?????????MOV?????r0,?#2_0110
?????????MCR?????p15,?0,?r0,?c2,?c0,?0 ;Cache
?????????MCR?????p15,?0,?r0,?c3,?c0,?0 ;寫緩存
;?開(kāi)啟access?允許
?????????MOV?????r0,?#2_11111100
?????????MCR?????p15,?0,?r0,?c5,?c0,?0 ;允許訪問(wèn)
;
;?設(shè)置全局配置?
;
?????????MRC?????p15,?0,?r0,?c1,?c0,?0 ;讀CP15寄存器到r0
?????????ORR?????r0,?r0,?#(0x1?<<2)? ;開(kāi)啟Cache????????
?????????ORR?????r0,?r0,?#0x1 ;開(kāi)啟MPU
?
;
;增加的配置選項(xiàng)
;????????
;????????ORR?????r0,?r0,?#(0x1?<<13)? ;開(kāi)啟Hi?Vectors
;????????ORR?????r0,?r0,?#(0x1?<<7)? ;開(kāi)啟大端模式
?????????MCR?????p15,?0,?r0,?c1,?c0,?0 ;寫CP15寄存器c1
?????????MOV?????pc,lr ;返回
?????????END
上述程序端可作為參考,可以在程序中直接使用,也可以作為子程序被其他程序調(diào)用。如果作為子程序調(diào)用,下面兩種調(diào)用方式作為參考。
①?在匯編程序中調(diào)用。
????IMPORT?Cache_Init
????BL?Cache_Init
②?在C語(yǔ)言中調(diào)用。
extern?void?Cache_Init(void);
Cache_Init();