ARM3級(jí)流水和5級(jí)流水為什么都是PC=PC+8
arm7采用三級(jí)流水
(1)取指(fetch)
取指級(jí)的任務(wù)是從程序存儲(chǔ)器中讀取指令。
(2)譯碼(decode)
譯碼級(jí)完成對(duì)指令的分析,并為下一個(gè)周期準(zhǔn)備數(shù)據(jù)路徑需要的控制信號(hào)。在這一級(jí),指令占用譯碼邏輯,不占用數(shù)據(jù)通路。
(3)執(zhí)行(excute)
完成指令要求的操作,并根據(jù)需要將結(jié)果寫(xiě)回寄存器。指令占用數(shù)據(jù)路徑,寄存器堆被讀取,操作數(shù)在桶行移位器中被移位。運(yùn)算器產(chǎn)生運(yùn)算結(jié)果并回寫(xiě)到目的寄存器中,運(yùn)算器根據(jù)指令需求和運(yùn)輸結(jié)果更改狀態(tài)寄存器的條件位。
arm9采用五級(jí)流水
(1)取指(fetch)
從存儲(chǔ)器中取出指令,并將其放入指令流水線。
(2)譯碼(decode)
指令被譯碼,從寄存器堆中讀取寄存器操作數(shù)。在寄存器堆中有3個(gè)操作數(shù)讀端口,因此大多數(shù)ARM指令能在1個(gè)周期內(nèi)讀取其操作數(shù)。
(3)執(zhí)行(execute)
將其中一個(gè)操作數(shù)移位,并在ALU中產(chǎn)生結(jié)果。如果指令是Load或Store指令,則在ALU中計(jì)算存儲(chǔ)器的地址。
(4)緩沖/數(shù)據(jù)(buffer/data)
如果需要?jiǎng)t訪問(wèn)數(shù)據(jù)存儲(chǔ)器,否則ALU只是簡(jiǎn)單地緩沖一個(gè)時(shí)鐘周期,以便是所有的指令具有同樣的流水線流程。
(5)回寫(xiě)(write-back)寄存器堆
------------------------------------------------
注意,arm7中執(zhí)行和取指是隔了一級(jí)譯碼級(jí),那一級(jí)不讀取數(shù)據(jù),當(dāng)前PC=原PC+8, 正常
arm9中執(zhí)行和取指之間的譯碼級(jí)不再老實(shí),譯碼級(jí)已經(jīng)開(kāi)始從寄存器堆中讀取寄存器操作數(shù),這樣的話,
讀取到得就是PC+4,不是PC+8,執(zhí)行級(jí)又不會(huì)再讀一次,那將導(dǎo)致執(zhí)行級(jí)的PC還是=PC+4
為了保持向下兼容,在ARM9的5級(jí)流水線上,取指級(jí)增加的PC值被直接送到譯碼級(jí)的寄存器,穿過(guò)了兩級(jí)之間的流水線寄存器,這樣譯碼級(jí)得到的PC值就是下一條指令的PC+4,等于當(dāng)前指令的PC+8,
等到了執(zhí)行級(jí)時(shí),PC寄存器的值=當(dāng)前指令地址+8
當(dāng)使用指令STR或STM對(duì)R15進(jìn)行保存時(shí),保存的可能是當(dāng)前指令地址加8或當(dāng)前指令地址加12。
到底是哪種方式,取決于芯片的具體設(shè)計(jì)方式。當(dāng)然,在同一個(gè)芯片中,只能采用一種方式。要么保存當(dāng)前指令地址加8,要么保存當(dāng)前指令地址加12。程序開(kāi)發(fā)人員應(yīng)盡量避免使用STR或STM指令來(lái)對(duì)R15進(jìn)行操作。當(dāng)不可避免要使用這種方式時(shí),可以先通過(guò)一小段程序來(lái)確定所使用的芯片是使用哪種方式實(shí)現(xiàn)的。例如:
SUB R1,PC, #4 ;R1中存放STR指令地址
STR PC,[R0] ;用STR指令將PC保存到R0指向的地址單元中,
;PC=STR指令地址+偏移量(偏移量為8或者12)。
LDR R0,[R0] ;讀取STR指令地址+偏移量的值
SUB R0,R0,R1 ; STR指令地址+偏移量的值減去STR指令的地址,
;得到偏移量值(8或者12)。
=============================
ARM7采用三級(jí)流水線的馮·諾伊曼結(jié)構(gòu),ARM9采用五級(jí)流水線的哈佛結(jié)構(gòu)。
ARM7流水線包括取指(fetch)、譯碼(decode)、執(zhí)行(excute)。ARM7流水線在譯碼階段不讀取操作數(shù)寄存器,因此執(zhí)行階段的PC值和取指階段的PC值關(guān)系為:PC(excute)=PC(fetch)+8。
ARM9流水線包括取指(fetch)、譯碼(decode)、執(zhí)行(excute)、緩沖/數(shù)據(jù)(buffer/data)、回寫(xiě)(write-back)寄存器堆。ARM9流水線在譯碼階段已經(jīng)開(kāi)始讀取操作數(shù)寄存器,因此譯碼階段的PC值和取指階段的PC值關(guān)系為:PC(decode)=PC(fetch)+4。因此執(zhí)行階段的PC值和譯碼階段的PC值關(guān)系為:PC(excute)=PC(decode)+4。
為了保證ARM9流水線和ARM7流水線兼容,ARM9流水線將取指階段的PC值跨過(guò)取指和譯碼流水線寄存器,直接送往譯碼階段寄存器,這樣仍然保證執(zhí)行階段的PC值和取指階段的PC值關(guān)系為:PC(excute)=PC(fetch)+8。以下面uboot中的start.S的最開(kāi)始的匯編代碼為例來(lái)進(jìn)行解釋?zhuān)?p>
00000000 <_start>:
0: ea000014 b 58
4: e59ff014 ldr pc, [pc, #20] ; 20 <_undefined_instruction>
8: e59ff014 ldr pc, [pc, #20] ; 24 <_software_interrupt>
c: e59ff014 ldr pc, [pc, #20] ; 28 <_prefetch_abort>
10: e59ff014 ldr pc, [pc, #20] ; 2c <_data_abort>
14: e59ff014 ldr pc, [pc, #20] ; 30 <_not_used>
18: e59ff014 ldr pc, [pc, #20] ; 34 <_irq>
1c: e59ff014 ldr pc, [pc, #20] ; 38 <_fiq>
00000020 <_undefined_instruction>:
20: 00000120 .word0x00000120
復(fù)制代碼
下面對(duì)每一個(gè)指令周期,CPU做了哪些事情,分別詳細(xì)進(jìn)行闡述:
在看下面具體解釋之前,有一句話要牢記,那就是:
PC不是指向你正在運(yùn)行的指令,而是
PC始終指向你要取的指令的地址。
認(rèn)識(shí)清楚了這個(gè)前提,后面的舉例講解,就容易懂了。
指令周期Cycle1
(1)取指:
PC總是指向?qū)⒁x取的指令的地址(即我們常說(shuō)的,指向下一條指令的地址),而當(dāng)前PC=4,
所以去取物理地址為4對(duì)對(duì)應(yīng)的指令“ldr pc,[pc,#20]”,其對(duì)應(yīng)二進(jìn)制代碼為e59ff014。
此處取指完之后,自動(dòng)更新PC的值,即PC=PC+4(單個(gè)指令占4字節(jié),所以加4)=4+4=8
指令周期Cycle2
(1)譯指:翻譯指令e59ff014;
(2)同時(shí)再去取指:
PC總是指向?qū)⒁x取的指令的地址(即我們常說(shuō)的,指向下一條指令的地址),而當(dāng)前PC=8,
所以去物理地址為8所對(duì)應(yīng)的指令“ldr pc,[pc,#20]”其對(duì)應(yīng)二進(jìn)制代碼為e59ff014。
此處取指完之后,自動(dòng)更新PC的值,即PC=PC+4=8+4=12=0xc
指令周期Cycle3
(1)執(zhí)行(指令):執(zhí)行“e59ff014”,即“ldr pc,[pc,#20]”所對(duì)表達(dá)的含義,即
PC
= PC + 20
= 12 + 20
= 32
= 0x20
此處,只是計(jì)算出待會(huì)要賦值給PC的值是0x20,這個(gè)0x20還只是放在執(zhí)行單元中內(nèi)部的緩沖中。
(2)譯指:翻譯e59ff014。
(3)取指:
此步驟由于是和上面(1)中的執(zhí)行同步做的,所以,未受到影響,繼續(xù)取指,而取指的那一時(shí)刻,PC為上一Cycle
更新后的值,即PC=0xc,所以是去取物理地址為0xc所對(duì)應(yīng)的指令”ldr pc,[pc,#20]”,對(duì)應(yīng)二進(jìn)制為e59ff014。
評(píng)論