时序图 分支_BOOM微架构学习(1)——取指单元与分支预测
之前在RISC-V的“Demo”級項目——Rocket-chip一文中曾經簡介過BOOM處理器的流水線,這次我們開始一個系列,深入學習一下BOOM的微架構,這樣對于亂序執行的超標量處理器會有一個較為深入的認識。
本系列計劃按照流水線的前后順序,第一篇講前端的取指和分支預測,第二篇講譯碼和寄存器重命名,第三篇介紹ROB和指令的發射,第四篇介紹指令的執行和Bypass機制,第五篇講BOOM的訪存和存儲系統, 最后從使用的角度來講一下BOOM中的Chisel Parameter配置方式。
本文是BOOM系列的第一篇,先從取指單元以及BOOM的分支預測器入手。
BOOM的取指單元
在介紹取指單元之前先回顧兩個概念方便下文討論:一個叫前端(Front-end),指流水線中的取指和分支預測部分,這一部分將指令從I-Cache中取出;另一個叫后端(Back-end),指流水線中從派發到寫回階段的這一部分,也就是指令的執行階段。
BOOM的前端如下圖所示,它包括取指和分支預測在內共劃分為5個周期(從F0到F4)。當后端發現分支預測錯誤,或者分支預測器預測需要改變取指的位置,就會給前端發一個請求,前端就會從新的PC開始取指令。
BOOM前端架構圖BOOM并不是每次從I-Cache中取一條指令,而是一次從指令緩存中取出一個Fetch Packet的指令(就像是批發一樣,一次批發一包指令進來)。之后對這些指令進行快速譯碼(為分支預測提供信息),并寫到Fetch Buffer(Fetch Buffer是一個將前后端解耦的指令隊列)中供后端使用;同時將給后端用的PC和分支預測信息則寫到Fetch Target Queue中(Fetch Target Queue保存著從I-Cache取得的指令的地址以及地址對應的分支預測信息;當指令被提交后,ROB會從Fetch Target Queue中取出該指令的相應信息;當取指單元重定向時Fetch Target Queue會被更新)。
另外,BOOM必須要考慮RVC指令,RVC指令是RISC-V標準中規定的16位壓縮指令,目的在于減少程序代碼空間大小。取RVC指令給處理器帶來了很大的挑戰,主要在于加入了16位指令以后,原有的32位指令不再是要求4字節對齊的了,這樣一來有的指令是從半字節位置開始,找到一條指令的起始位置就變得困難;而且譯碼的復雜度也增加了(操作數的位置不再固定為指令低7位);每次PC的自增也不再是簡單的PC+4。
這樣,一條指令從指令緩存中取出來,到寫入Fetch Buffer之前,要經歷如下的過程: 1. Fetch Packet的大小為fetchWidth*16位,在F2周期每次從I-Cache中取出一個Fetch Packet大小的指令存放到IMem Response Queue中, 2. 在F3周期中維護取指“狀態”,包括上一個Fetch Packet的最后16位(有可能上一個Fetch Packet的最后16位和本Fetch Packet的前16位共同組成一條指令)、PC等,用于解決RVC指令的若干問題。F3中還包括了預譯碼單元,用于確定每條指令的起始位置。 3. 在存到Fetch Buffer前將無效指令去掉
BOOM的分支預測
接下來我們來討論BOOM的分支預測機制。 BOOM使用了兩級分支預測,第一級是快速而簡單的Next-Line Predictor(NLP),第二級是慢速而復雜的Backing Predictor(BPD)。
Next-Line Predictor(NLP)
總的來說BOOM的NLP是由一個全相連的Branch Target Buffer(BTB)、一個雙峰表(BIM)以及一個返回地址棧(RAS)組成的快速而“相對”準確的預測器。它可以根據當前PC在一個周期內(通過組合邏輯)完成預測,在大多數情況下BOOM使用NLP可以快速作出分支預測的決定。
NLP的預測
NLP中的BTB如下圖所示。和一般簡單的處理器不同的是,NLP的預測不是基于某條指令進行分支預測的判斷,而是根據一整個Fetch Packet進行判斷。 每次預測時,NLP首先將Fetch PC(即當前Fetch Packet的開頭的地址)和BTB中的PC tags進行匹配, 如果發現有匹配上的項,BTB和RAS一起判斷該Fetch Packet中是否包含分支、跳轉或者返回指令,以及具體是哪條指令發生了跳轉(記錄在BTB的bidx字段中)。
BOOM的BTB當確定某條指令為分支指令時,NLP會查詢BIM表來決策跳轉還是不跳轉;當確定某條指令為返回指令時,NLP會查詢RAS來確定下一次取指的Fetch PC。
NLP的更新
當前端發生重定向、后端發出了跳轉請求(一般意味著分支預測錯誤)或者BPD做出了分支預測時,BTB會更新或創建新的表項。
當前端的預先譯碼發現某指令為“Call”指令時(RISC-V并沒有專門定義的Call指令,BOOM通過JAL和JALR指令的目標寄存器為x1判定該指令為調用指令),會將它的PC和它的目標PC壓入RAS中;當發現某條指令為返回指令時,將該項從RAS中彈出。
Backing Predictor(BPD)
介紹完了簡單的NLP(實際上確實很簡單,很短的篇幅就把NLP的工作過程講清楚了),接下來本段要講的第二級分支預測器BPD就比較復雜了。
正常情況下NLP在預測正確的情況下,后端可以不間斷地執行指令。 但NLP在具有簡單快速的優點的同時也帶來了很多缺點:比如面積和功耗較大、BTB的存儲空間有限,只能存儲幾十個分支、BIM的機制太過簡單,無法應對復雜的跳轉情況。
為了解決這些問題BOOM提供了BPD,它的目標是利用很小的面積來作出相當高準確率的判斷;BPD只能判斷某條分支指令(無條件跳轉指令不在BPD的職責范圍之內,它們由NLP和后端共同負責處理)是否需要跳轉,而無法給出哪些指令是分支指令以及它們跳轉的目標是什么(這些信息可以從BTB中獲得,也可以從F3周期的預先譯碼模塊中獲得)。 當BPD作出預測時,它會給出一個比特序列,該序列的長度與配置的Fetch Width相同,即對Fetch Packet中的每條指令給出“跳轉”或“不跳轉”的決策(當然只有分支指令對應的比特位才是有意義的),在F3周期會對Fetch Packet中的指令進行預先譯碼,解出每條指令的分支目標地址,并結合BPD給出的比特序列決定是否對前端進行重定向。
從本文開頭的BOOM前端時序圖中可以看出,BPD的作用是橫跨整個取指過程的,與訪問Cache和NLP的預測并行, 這樣就為BPD爭取到了三個時鐘周期的時間,這樣BPD可以將龐大的歷史記錄存放在SRAM中,而不必須像BTB一樣使用寄存器存儲,節約了很大的面積。
講完了BPD在前端的大致作用,接下來我們開始剖析BPD的若干細節。
全局歷史寄存器(GHR)
BPD采用了基于全局歷史的分支預測設計,它使用全局歷史寄存器(Global History Registor, GHR)來預測本條指令是否需要跳轉。 GHR中記錄了之前N條分支指令的結果。在對某條分支指令進行預測時,GHR根據之前N條分支指令的跳轉結果來作出決策,這就意味著GHR必須跟著每條分支指令即時進行更新。而對于BOOM來說,指令只有過了Commit階段,才能真正“確定”被執行了,此時更新到GHR中才能保證絕對不會出錯。 但這對于BOOM來說太晚了,可能同時有多條指令在BOOM的流水線中運行著,也就意味著BPD對于某條分支指令的預測時根據多條指令以前的歷史信息進行的判斷,準確度是不夠的。
因此在BOOM中GHR采用的是推測式更新法,當某條分支指令被預測后,就會更新在GHR中。當后端發現某條分支指令預測錯誤時,就需要重置并更新正確的GHR,因此對于流水線中正在執行的每條分支指令,均保留了它當時的GHR快照,以便后面需要時進行恢復。
分支預測抽象類
BOOM定義了一個分支預測抽象類BranchPredictor,實現這個類即可為BOOM實現一種新的基于全局歷史的分支預測方案。 BranchPredictor為BPD的實現提供了接口以及GHR的控制邏輯,實現類不需要再去處理上文中提到的有關GHR的更新、快照維護等事情,而專注于分支預測的邏輯即可。分支預測抽象類的接口邏輯結構如下圖所示。
BOOM的抽象分支預測類框圖2-bit計數器表
BPD中專門設計了一個2-bit計數器表(Two-bit Counter Table,簡稱2BCT)供各種分支預測器使用。 在此先復習一下2-bit計數器的知識,0b11代表“強烈跳轉”,而0b00代表“強烈不跳轉”;因此,高位代表“是否跳轉”,簡稱P位,而低位代表“強度”,簡稱H位。
在BOOM中,為了節約面積將2BCT存入SRAM中,對2-bit計數器進行了調整:如果當前狀態為0b10,而此次輸入為“沒有跳轉”,則狀態直接轉移到0b00;如果當前狀態為0b01,而此次輸入為“跳轉”,則狀態直接轉移到0b11。調整后的時序轉移圖如下。
經過這樣的調整以后,P位和H位可以在硬件上分開進行設計: 對于P位來說,每次預測時讀取從而進行是否跳轉的判斷,而每次判斷錯誤時則進行取反寫入;對于H位來說,在預測錯誤時進行讀取,而每次分支指令執行后進行寫入(寫入分支結果)。
通過這種設計BOOM將P位和H位分別存儲于兩個1端口SRAM中。
GShare預測器
本文最后介紹BOOM實現的兩種分支預測器,分別是本節將要介紹的GShare預測器以及下一節中的TAGE預測器。
GShare分支預測器實現比較簡單,下圖為其邏輯框圖。它將GHR與指令的PC做異或后,作為2BCT的索引進行查詢和更新。
GShare預測器TAGE預測器
TAGE(TAgged GEometric)是一種新型的高度可配置的分支預測算法,它既能快速學習短期歷史,也能學習長期歷史(可以學習超過1000條分支歷史記錄)。
TAGE預測器TAGE由一組預測表構成,每張表包括了一個預測計數器、一個有用度計數器以及一個tag。預測計數器用于提供預測,有用度計數器記錄著在過去的正確預測中該表項的重要程度,tag用于進行匹配。
TAGE的每一張表都擁有不同長度的歷史記錄(基本上可以理解為上文中的GHR),每張表的歷史記錄和要預測的指令PC進行異或得到index hash和tag hash。在每張表中先通過index hash進行索引再通過tag hash進行匹配,根據該表項做出預測。在所有作出預測的表中,選擇歷史記錄最長的表作為最終的預測結果。
有關TAGE的更多細節(可以另寫一篇文章)讀者可自行搜索學習,本文限于篇幅不再詳述。
本文小結
本文作為BOOM微架構學習系列第一篇,介紹了BOOM的取指模塊及其分支預測器的設計。在分支預測器部分,介紹了BOOM的兩級分支預測:NLP和BPD。其中BPD是基于全局歷史的復雜分支預測設計,可以實現多種分支預測算法。本文介紹了Gshare和TAGE兩種預測器,當然BOOM也還支持其他的預測器,讀者可以自行查閱相關資料。
參考資料
[1] https://docs.boom-core.org/
總結
以上是生活随笔為你收集整理的时序图 分支_BOOM微架构学习(1)——取指单元与分支预测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关闭笔记本显示器指定组合键才能打开_笔记
- 下一篇: excel中match函数_Excel函