|
Cache是高性能CPU解決總線訪問速度瓶頸的方法,然而它的使用卻是需要權(quán)衡的,因?yàn)榫彺姹旧淼膭?dòng)作,如塊拷貝和替換等,也是很消耗CPU時(shí)間的。MMU的重要性勿庸置疑,ARM920T(和ARM720T)集成了MMU是其最大的賣點(diǎn);有了MMU,高級(jí)的操作系統(tǒng)(虛擬地址空間,平面地址,進(jìn)程保護(hù)等)才得以實(shí)現(xiàn)。二者都挺復(fù)雜,并且在920T中又高度耦合,相互配合操作,所以需要結(jié)合起來研究。同時(shí),二者的操作對(duì)象都是內(nèi)存,內(nèi)存的使用是使用MMU/Cache的關(guān)鍵。另外,MMU和Cache的控制寄存器不占用地址空間,CP15是操縱MMU/Cache的唯一途徑。
Cache/Write Buffer的功
Cache通過預(yù)測(cè)CPU即將要訪問的內(nèi)存地址(一般都是順序的),預(yù)先讀取大塊內(nèi)存供CPU訪問,來減少后續(xù)的內(nèi)存總線上的讀寫操作,以提高速度。然而,如果程序中長(zhǎng)跳轉(zhuǎn)的次數(shù)很多,Cache的命中率就會(huì)顯著降低,隨之而來,大量的替換操作發(fā)生,于是,過多的內(nèi)存操作反而降低了程序的性能。
ARM920T內(nèi)部采用哈佛結(jié)構(gòu),將內(nèi)部指令總線和數(shù)據(jù)總線分開,分別連接到ICache和DCache,再通過AMBA(高級(jí)微控制器總線結(jié)構(gòu))總線接口連接到ASB總線上去訪問內(nèi)存。Cache由Line組成,Line是Cache進(jìn)行塊讀取和替換的單位。
Writer Buffer是和DCache相逆過程的一塊硬件,目的也是通過減少memory bus的訪問來提高性能。
MMU的功能
在內(nèi)存中維護(hù)一張或幾張表,就看你怎么給內(nèi)存劃分page和section了。通過CP15指定好轉(zhuǎn)換表的位置,920T的硬件會(huì)自動(dòng)將轉(zhuǎn)換表的一部分讀到TLB中。CPU每次進(jìn)行內(nèi)存讀寫時(shí),發(fā)出虛擬地址,參照TLB中的轉(zhuǎn)換表轉(zhuǎn)換到物理地址,并讀取相應(yīng)entry中的信息,以決定是否可以有權(quán)限讀寫和緩存。
mmugen這個(gè)工具就是幫你構(gòu)造這個(gè)表的,省的自己寫程序了。
操作MMU,實(shí)際上就是如何分配和使用你的內(nèi)存,并記錄在translationtable里。
ARM920T中,MMU的每條entry包括Cachable和Buffable位來指定相應(yīng)的內(nèi)存是否可以用Cache緩存。此處就是MMU與Cache的交互作用處。
實(shí)際上,MMU和Cache的使用是操作系統(tǒng)設(shè)計(jì)者根據(jù)系統(tǒng)軟硬件配置而考慮的事情。操作系統(tǒng)針對(duì)分配給應(yīng)用程序的地址空間作內(nèi)存保護(hù)和緩存優(yōu)化。在沒有操作系統(tǒng)的情況下,就需要我們自己來掌控它們了。其中,主要是合理分配內(nèi)存。
我認(rèn)為,以下幾點(diǎn)需要著重考慮:
1) 安全第一! -- 避免MMU和Cache的副作用。
當(dāng)你在無OS的裸機(jī)上開發(fā)程序時(shí),初始化運(yùn)行環(huán)境的代碼很重要,比如:各種模式堆棧指針的初始化;將代碼和RW data從ROM拷貝到RAM;初始化.bss段(zero initialized)空間等。此時(shí)會(huì)有大量的內(nèi)存操作,如果你enable了Cache,那么在拷貝完代碼之后,一定要invalidate ICache和flush DCache。否則將會(huì)出現(xiàn)緩存中的代碼或數(shù)據(jù)與內(nèi)存中的不一致,程序跑飛。
另外,有時(shí)候我們需要自己作loader來直接運(yùn)行ELF文件,情況也是一樣,拷貝完代碼后一定要刷新Cache,以免不測(cè)。
還有,對(duì)硬件的操作要小心。很多寄存器值都是被硬件改變的,讀寫時(shí),要保證確實(shí)訪問到它的地址。首先,在C語言代碼中聲明為volatile變量,以防止內(nèi)存讀寫被編譯器優(yōu)化掉;另外,設(shè)置好TLB,使得寄存器映射的地址空間不被緩存。
總之,緩存和內(nèi)存中代碼的不一致,是一定要避免的。
2) 弄巧成拙! -- 只對(duì)頻繁訪問的地址空間進(jìn)行Cache優(yōu)化。
我們很清楚自己的程序中,那里有大量的運(yùn)算,哪里有無數(shù)的循環(huán)或遞歸,而這正是Cache的用武之地,我們將這些空間進(jìn)行緩存將大大提高運(yùn)行速度。但是,很多函數(shù)或子程序往往僅僅運(yùn)行很少幾次,若是對(duì)它們也緩存,只會(huì)撿了芝麻丟了西瓜,造成不必要的緩存和替換操作,反而增加了系統(tǒng)負(fù)擔(dān),降低了整體性能。
3) 斷點(diǎn)哪兒去了? -- 如何調(diào)試“加速”了的代碼?
據(jù)我所知,一般,debugger都是通過掃描地址總線,在斷點(diǎn)處暫停CPU。ARM9TDMI中集成的JTAG調(diào)試口,也是這樣。
當(dāng)我們調(diào)試使用Cache的代碼時(shí),將會(huì)出現(xiàn)問題。比如:CPU訪問某斷點(diǎn)所在地址之前的地址時(shí),發(fā)生緩存操作,斷點(diǎn)處代碼被提前讀入Cache,此時(shí)地址總線上出現(xiàn)了斷點(diǎn)地址,CPU被debugger暫停,并且斷點(diǎn)之后的指令也被Cache緩存。于是,當(dāng)你從斷點(diǎn)處step時(shí),程序卻停不了了,因?yàn)榈刂房偩上不再出現(xiàn)斷點(diǎn)之后的下一個(gè)地址了。
再舉個(gè)例子:
int i,a;
for (i=0; i<100; i++) {
-> a++; /* set breakpoints */
}
當(dāng)?shù)刂房偩上第一次出現(xiàn)斷點(diǎn)地址時(shí),CPU暫停;之后,就再也不會(huì)停了。因?yàn),之后CPU會(huì)從cache中直接去代碼了。(當(dāng)然,后來,Cache的代碼有可能會(huì)被替換掉,斷點(diǎn)又可到達(dá)。) 所幸的是,我用的debugger提供JTAG Monitor,允許斷點(diǎn)跟蹤使用cache的程序。
以下課程可免費(fèi)試聽C語言、電子、PCB、STM32、Linux、FPGA、JAVA、安卓等。
想學(xué)習(xí)的你和我聯(lián)系預(yù)約就可以免費(fèi)聽課了。
宋工企鵝號(hào):3524-6590-88 Tel/WX:173--1795--1908
|
|