ARM 流水線技術:
常常在講ARM流水線的時候,很多同學就很暈,後來調查了一下,大多數同學都是不同熟悉指令導致的。為了讓大家更好的流水線,在這裡先簡單的介紹ARM的一部分指令集。
一、部分ARM指令
在學ARM指令之前,要知道一個常識,就是我們的指令可是直接給ARM核執行的,每條指令都應該包含兩部分內容:(1)執行的指令 (2)操作的資料。
思考,此時我們把資料都儲存在哪裡呢?
要想回答這個問題,必須知道ARM核能直接操作的儲存單元是誰呀,呵呵,是寄存器。對,我們就把我們的資料存放在寄存器中,然後ARM直接就可以從寄存器中讀取資料,根據相應的指令,做出相應的處理。當然ARM也可以讀取記憶體中的資料的,此時需要用到ldr指令。
1.載入資料到寄存器
(1)載入一個立即數到寄存器
mov 寄存器,#立即數
什麼是立即數呢?先不要研究這個問題,研究這個問題沒有意義,如果你寫的不是的資料不是一個合法的立即數,編譯器會報錯的。不過,可以告訴大家的是,能用一個位元組標識的資料,都可以認為是合法立即數。
還有一個地方要注意,在立即數的前面要加上"#",表示後面的資料是一個立即數。
例如:給r0,寄存器賦值為10
movr0,#10
(2)用ldr載入任意資料到寄存器
ldr 寄存器,=資料
記住這麼寫就可以了,後面我們會解釋為什麼的。
例如:將0x12345678載入到r1寄存器
ldr r1,=0x12345678
(3)將寄存器的值寫到記憶體
str 寄存器,[地址]
注意,這裡的"[]"一定不能丟了
例如,將寄存器r1的值,寫到0x30008000這個地址
movr1,#100
ldr r2,=0x30008000
str r,[r2]
(4)從記憶體中載入資料到寄存器
ldr 寄存器,[地址]
注意,這裡的"[]"一定不能丟了
例如:從0x30008000這個地址讀取資料到r1寄存器
ldrr0,=0x30008000
ldrr1,[r0]
2.加、減運算指令
(1)加法指令
add 寄存器,運算元1,運算元2
這裡的寄存器是用來存放,運算元1,運算元2相加的結果的,其中運算元1必須是寄存器,操作2可以是寄存器也可以是立即數
例如:
addr2,r0,r1
等價於r2 = r0 + r1
addr2,r0,#3
等價於r2 = r0 + 3
(2)減法指令
sub 寄存器,運算元1,運算元2
這裡的寄存器是用來存放,運算元1 減去 運算元2的結果的,其中運算元1必須是寄存器,操作2可以是寄存器也可以是立即數
例如:
subr2,r0,r1
等價於r2 = r0 - r1
subr2,r0,#3
等價於r2 = r0 - 3
3.與,或運算子
(1)與運算
and 寄存器,操作1,運算元2
這裡的寄存器是用來存放,運算元1 與 上 運算元2的結果的,其中運算元1必須是寄存器,操作2可以是寄存器也可以是立即數
例如:將r0寄存器的值與上0x23的結果寫入r0
andr0,r0,#0x23
(2)或運算
orr 寄存器,操作1,運算元2
這裡的寄存器是用來存放,運算元1 或 上 運算元2的結果的,其中運算元1必須是寄存器,操作2可以是寄存器也可以是立即數
例如:將r0寄存器的值或上0x23的結果寫入r0
orrr0,r0,#0x23
4.跳轉指令
(1)b 指令
b指令跳轉到指定的地址執行程式。
例如: 跳轉到地址0x30008000地址去執行
b 0x30008000
有些時候,在組譯工具裡面,我們可以設定一個標號,可以直接通過b指令跳到對應的標號
b next
....
....
next:
....
stop:
b stop
(2)bl 指令
bl指令在跳轉到指定地址執行程式前,將下一條指令的地址拷貝到R14(lr)連結寄存器中。
在這裡大家可以思考一下,bl指令比b指令有哪些優勢?
5.條件執行
所有的ARM指令都可以條件執行,而Thumb指令只有B(跳轉)指令具有條件執行 功能。如果指令不標明條件代碼,將預設為無條件(AL)執行。
常用的條件:
EQ 相等
NE 不相等
....
還有很多哦,先只說兩個
例如:
start:
subr0,r0,#1
cmp r0,#3
beq next
bne start
6.多寄存器載入指令LDM
多寄存器載入可以實現在一組寄存器和一塊連續的記憶體單元之間傳輸資料。LDM為載入多個寄存器;
LDM{cond}<模式> Rn{!},reglist{^}
cond:指令執行的條件;
模式:控制地址的增長方式,一共有8種模式;
!:表示在操作結束後,將最後的地址寫回Rn中;
reglist:表示寄存器列表,可以包含多個寄存器,它們使用“,”隔開,如{R1,R2,R6-R9},寄存器由小到大排列;
^:加入該尾碼後,進行資料傳送且寄存器列表不包含PC時,載入/儲存的寄存器是使用者模式下的,而不是當前模式的寄存器。若在LDM指令且寄存器列表中包含有PC時使用,那麼除了正常的多寄存器傳送外,還將SPSR也拷貝到CPSR中,這可用於異常處理返回。注意:該尾碼不允許在使用者模式或系統模式下使用。
例如:
LDMIA R13!, {R0-R3}
LDM指令的功能是將對應地址空間的內容載入到寄存器,IA(increase after)指的是載入完後,地址自動加4
! 指的是地址增加後,要寫入R13寄存器
例如:R13的值是0x30000,
指令執行完後,R0的值為12,R1的值為13,R2的值為14,R3的值為15,R13的值為0x300f
好了就這麼多吧,學這些指令的目的是讓大家能看懂流水線做的鋪墊,後面我們會單獨花時間來講解指令集的。
二、ARM的流水線
一條指令執行的過程
簡單來說,執行某條指令至少要通過取指、解碼、執行三個步驟。這就好像盲人在吃飯,第一步是用筷子夾出要吃的東西(從記憶體中取出指令),第二步是把吃的東西舉到鼻子底下聞一下看看是否能吃(分析該指令),第三步是放到嘴裡吃(執行指令)。
我們假設盲人又只有一隻手,而每一個步驟都要一秒鐘的時間,那麼這位盲人至少需要三秒鐘才能吃到一樣東西,很顯然這種吃飯的方法效率低。所以,如果CPU也採取同樣的方法,像上圖那樣去執行一條指令,那就意味著 CPU需消耗3個指令周期才能完成一個動作,可見其運行效率的低下。
為了彌補這個問題,ARM採用了一種多級流水線的指令執行方式。例如,在ARM7就採用了三級流水線的處理方法,如下圖所示:
如上圖,CPU採用流水線作業的方式,在大多數情況下,是利用三個刻度的時間去執行三條指令,從而大大提高了代碼運行效率。
這就好像一位樂於助人的科學家,知道了盲人吃飯的故事之後,給這位盲人製作了兩隻機械手,現在盲人已經有三隻手了,那麼他會怎樣吃飯呢?當他的第一隻手把吃的送到嘴裡吃的時候(執行指令),第二隻手已經將另外的食物湊到鼻子底下聞了(分析指令),而第三隻手此時正在從盤子裡夾第三樣東西呢。從此,盲人吃飯的效率就提高了三倍。
理解了嗎,這就是流水線的好處。下面,來看一些典型的流水線。
1.ARM7的三極流水線
為增加處理器指令流的速度,ARM7 系列使用3級流水線.
允許多個操作同時處理,而非順序執行。
PC指向正被取指的指令,而非正在執行的指令
(1)最佳流水線執行個體:
該例中用6個刻度執行了6條指令
所有的操作都在寄存器中(單周期執行)
指令周期數 (CPI) = 1
呵呵,CPI=1是最理想的流水線了,但在很多時候,很難達到這樣的效果。例如,出現多周期指令、跳轉分支指令和中斷髮生的時候,流水線都會阻塞,而且相鄰指令之間可能因為寄存器衝突導致流水線阻塞,降低流水線的效率。
(2)帶有儲存空間訪問指令的流水線
該例中,用6周期執行了4條指令
指令周期數 (CPI) = 1.5
通過上圖可以知道,由於LDR指令要從記憶體中載入資料到寄存器。所以整個過程就可以分為訪問記憶體,然後寫寄存器。注意此時的訪問記憶體和寫寄存器都是在執行單元進行的,此時仍然佔用執行單元。這樣後面一條指令就不能使用執行單元,此時流水線被阻隔。
(3)含有分支指令的流水線
流水線被阻斷
注意:核心運行在ARM狀態
分支指令在其第一周期計算分支的目的地,同時在現行PC處完成一次指令預取。這種預取在任何情況下都要做的,因為當判決地址產生時已來不及停止預取。
第二個周期在分支的目標地址完成取指,而返回地址則存於R14如果link位已設定。
第三周期完成目標地址+4的取指,重新填滿流水線,並且如果跳轉是帶連結的還要修改R14(減去4)以便簡單地返回,需要三個刻度來執行,它所乾的事情就是修改lr的值即將lr的值減去4。
(4)中斷流水線
周期1: 核心被告知有中斷
IRQ在現行指令執行完之前不會被響應( MUL and LDM/STM 指令會有長的延遲)
解碼階段:中斷被解碼(中斷已使能,設定了相應標誌位… )。如果中斷被使能和服務,正常的指令將不會被解碼。
周期 2: 此時總是進入ARM狀態.
執行中斷 ( 擷取IR向量的地址), 儲存 CPSR 於 SPSR, 改變CPSR模式為 IRQ 模式並禁止進一步的 IRQ 中斷輸入。
周期 3: 儲存 PC (0x800C) 於 r14_irq, 從IRQ異常處理向量處取指
周期 4: 解碼向量表中的指令; 調整r14irq 為0x8008,即將r14irq的值減去4
周期 4和 5: 無有用的指令取指,由於周期 6的跳轉
周期 6: 取異常處理子程式的第一條指令;從子程式返回: SUBSpc,lr,#4
這將恢複工作模式並從響應中斷前的下一條指令處取指
如果有多個中斷,需堆棧儲存返回地址
2.ARM9的五級流水線
從上圖可以看到,ARM9設計的5級流水線,是將三極流水線中執行單元做的訪問記憶體 和寄存器回寫拆分成兩個單元進行執行。
(1)ldr互鎖
五級流水線只存在一種互鎖,即寄存器衝突。讀寄存器是在解碼階段,寫寄存器是在回寫階段。如果當前指令(A)的目的運算元寄存器和下一條指令(B)的源操 作數寄存器一致,B指令就需要等A回寫之後才能解碼。這就是五級流水線中的寄存器衝突。
本例中,用了7個刻度執行6條指令, CPI =1.2 。
LDR指令之後立即跟一條資料操作指令,由於使用了相同的寄存器,將會導致互鎖 。
(2)最佳流水線
本例中,用了6個刻度執行6條指令, CPI =1。
LDR指令沒有引起流水線互鎖
(3)LDM互鎖 1
由於LDMIA在執行的時候每次將記憶體的資料載入到寄存器後,會自動加地址值+4,注意這是一個加法操作,必須佔用E單元。從上圖可以看到在2,3,4之後。