一、非精確異常
在多發射亂序執行的流水線 cpu 上,從指令進入流水線到異常事件的發生,期間要經過若干流水級,此時 pc 的值已指向其後的某條指令,在實現非精確異常的 cpu 上就把此時的 pc 值作為引起異常指令的所在(為了表達的方便,記為 eptr)。
簡單地說就是 eptr 的指向,並非真正的引起異常的指令之所在,而是其後面的某條指令所在。
二、精確異常
簡單地說就是 eptr 的指向就是真正引起異常的指令之所在
而實現精確異常的 cpu,則在最後指令提交時 (commit) 按指令流的順序提交,異常的產生也在該指令提交時,這樣就能精確計算出引起異常的指令相對於當前 pc 的偏移,從而保證精確異常。
也就是說當異常產生時,之前的預備工作(即取指,解碼,當然pc隨之增長)便被廢棄。cpu從異常中返回時,再重新做讀取和解碼的工作。
總之,不管是何類異常,eptr 之前的所有指令都會被執行完成 (commit之後),eptr 之後的指令不會被執行。
三、mips 延遲槽
引入延時槽主要目的就是提高流水線的效率,分為以下兩種:
1、分支延時槽
分支延遲槽 (branch delay slot),簡單地說就是位於分支指令後面的一條指令,不管分支發生與否其總是被執行,而且通過下面的圖可以看出位於分支延遲槽中的指令先於目標指令提交 (commit即執行)。
進一步理解:
流水線中,分支指令執行時因為確定下一條指令的目標位址(緊隨其後 or 跳轉目標處?)一般要到第 2 步以後,在目標確定前流水線的取指級是不能工作的,即整個流水線就「浪費」(阻塞)了乙個時間片,為了利用這個時間片,在體系結構的層面上規定跳轉指令後面的乙個時間片為分支延遲槽(branch delay slot)。位於分支延遲槽中的指令總是被執行,與分支發生與否沒有關係。這樣就有效利用了乙個時間片,消除了流水線的乙個「氣泡」。
如下圖所示,當我們把延時槽的指令去掉以後,你會發現我們浪費了乙個時鐘週期。(還需要注意一點就是通過alu一條特殊路徑可以使分支跳轉位址提前半個時鐘週期獲得,加上延時槽指令取指階段的半個時鐘週期剛好為乙個時鐘週期,填充了我們浪費的乙個時鐘週期)
說明:延時槽當中的指令有兩個用途:
1)、用來傳遞子函式呼叫的引數
2)、延時槽指令的結果作為跳轉指令的條件。
2、儲存延時槽
資料載入指令的資料在下一條指令的alu階段啟動之後才能從快取或記憶體中取得,於是下一條指令不能使用該資料,如果下一條指令強制性的引用該資料,那麼該指令先停止執行(在alu階段),等這條資料載入指令完成了後再開始執行。
如下圖所示:
這樣完全不是原來被打斷的指令流,為了恢復原來的指令流需要將延時槽前面的跳轉指令重新裝入流水線(會再次執行延時槽中的指令,不過不一定在產生異常了)。
所以在延時槽中斷後返回的位址是前面跳轉指令的位址。
精確延時的實現
大家平時寫練習程式,包括 上的範例程式,很多延時都直接用的 sleep 實現。這個延時有個缺點,那就是無法統計 執行的時間。請看下圖 由圖可以看到,使用 api 函式 sleep 的問題,就是會忽略掉程式的執行時間。很多時候,程式的執行時間是不固定的,所以這就導致使用 sleep 的延時並不精確,即...
Systick精確延時0913
1.系統滴答定時器systick,核心自帶的24位遞減計數器,可計數2 24 1 16777215,計數到0後產生中斷標誌位countflag 時鐘可 於sysclk的8分頻或sysclk 2.systick相關暫存器 val load ctrl 3.systick的ctrl的第16位countfl...
STM32精確延時
前面用 stm32 的gpio 模擬液晶驅動 時序時遇到乙個問題,就是怎樣產生一段較為精確的延時。通常產生一小段延時的方法就是利用乙個遞增或者遞減迴圈進行軟體延時。例 void delay void 我在使用 mplab ide 進行pic 微控制器的開發時,mplab 提供了乙個 watch 跑錶...