ARM匯編編程基礎(chǔ)之二-流水線對PC值的影響
從上圖中我們看到CPU內(nèi)部有3個(gè)主要組成部分:指令寄存器,指令譯碼器,指令執(zhí)行單元(包括ALU和通用寄存器組)。
CPU在執(zhí)行1條指令的時(shí)候,主要有3個(gè)步驟:取指(將指令從內(nèi)存或指令cache中取入指令寄存器);譯碼(指令譯碼器對指令寄存器中的指令進(jìn)行譯碼操作,從而辨識出該指令是要執(zhí)行add,或是sub,或是其它操作,從而產(chǎn)生各種時(shí)序控制信號);執(zhí)行(指令執(zhí)行單元根據(jù)譯碼的結(jié)果進(jìn)行運(yùn)算并保存結(jié)果)
現(xiàn)在我們假設(shè)一下:CPU串行執(zhí)行程序(即:執(zhí)行完1條指令后,再執(zhí)行下一條指令);指令執(zhí)行的3個(gè)步驟中每個(gè)步驟都耗時(shí)1秒;整個(gè)程序共10條指令。那么,這個(gè)程序總的執(zhí)行時(shí)間是多少呢?顯然,是30秒。但這個(gè)結(jié)果令我們非常不滿意,因?yàn)樗?。有沒有辦法讓它座上京津高鐵提速3倍呢?當(dāng)然有!仔細(xì)觀察上圖,我們發(fā)現(xiàn):取指階段占用的CPU硬件是指令通路和指令寄存器;譯碼階段占用的CPU硬件是指令譯碼器;執(zhí)行階段占用的CPU硬件是指令執(zhí)行單元和數(shù)據(jù)通路。三者占用的CPU硬件完全不同,這樣就使得如下的操作得以進(jìn)行:在對第1條指令進(jìn)行譯碼的時(shí)候,可以同時(shí)對第2條指令進(jìn)行取指操作;在對第1條指令進(jìn)行執(zhí)行的時(shí)候,可以同時(shí)對第2條指令進(jìn)行譯碼操作,對第3條指令進(jìn)行取指操作。顯然,這樣就可以將該程序的運(yùn)行總時(shí)間從30秒縮減為12秒,提速近3倍。上面所述并行運(yùn)行指令的方式就被稱為流水線操作??梢姡毫魉€操作的本質(zhì)是利用指令運(yùn)行的不同階段使用的CPU硬件互不相同,并發(fā)的運(yùn)行多條指令,從而提高時(shí)間效率。
流水線的引入,的確提高了CPU運(yùn)行指令的時(shí)間效率,但卻為我們的匯編程序編寫引入了新的問題。請看下面的分析:
寄存器PC的值是即將被取指的指令的地址,正常情況下,在該條指令被取入CPU后執(zhí)行期間,PC的值保持不變,在該條指令執(zhí)行完成的時(shí)間點(diǎn)上,硬件會自動(dòng)將PC的值增加一個(gè)單位的大小,這樣PC就指向了下一條將被取指和執(zhí)行的指令。而在引入流水線后,PC值的情況發(fā)生了變化,假定第1條指令的內(nèi)存地址為X,則在時(shí)刻T,PC的值變?yōu)閄,并在時(shí)刻T至?xí)r刻T+1期間維持不變;在時(shí)刻T+1,PC的值變?yōu)閄+1個(gè)單位,并在時(shí)刻T+1至?xí)r刻T+2期間維持不變;在時(shí)刻T+2,PC的值變?yōu)閄+2個(gè)單位,并在時(shí)刻T+2至?xí)r刻T+3期間維持不變;在時(shí)刻T+3,PC的值將變?yōu)閄+3個(gè)單位。由此可見,在第1條指令的執(zhí)行階段,PC的值不再是該指令在內(nèi)存中的位置,而是該指令在內(nèi)存中的位置+2個(gè)單元。對于ARM指令集而言,每條指令的長度為32bit,占4byte,所以1條指令在內(nèi)存中需要4byte存儲。因此,我們的結(jié)論是:
指令執(zhí)行時(shí),PC的值 = 當(dāng)前正在執(zhí)行指令在內(nèi)存中的地址 + 8
請牢記以上結(jié)論。雖然目前我們并不明白這個(gè)結(jié)論有何作用,但在后續(xù)的課程中,特別是通過查看反匯編代碼的方式理解偽指令和編譯器行為的時(shí)候,這個(gè)結(jié)論將會很有幫助。
最后說明一點(diǎn):其實(shí)ARM現(xiàn)在的CPU的流水線級數(shù)早已經(jīng)突破了3級。但我仍然以3級流水線來進(jìn)行講解,是因?yàn)椋?、較之多級流水線,3級流水線最簡單,因此也最便于初學(xué)者理解;2、雖然存在多種級別的流水線,但ARM出于統(tǒng)一和前后兼容的考慮,PC的值 = 當(dāng)前正在執(zhí)行指令在內(nèi)存中的地址 + 8這個(gè)結(jié)論在所有的流水線級別上都是相同的。作為編程人員而言,我們只需要知道這個(gè)結(jié)論即可。
致謝:感謝安博中程的Michael Tang為本文制作了示意圖。
評論