P5 && P6-流水線CPU(verilog實現)(已更新)


能過P4,如果不是特殊情況,真別重搭                                                                 ---------一只大橙羊

存在一種方法,能夠讓一個人工作10個小時即可通過中強測,那就是重寫           ---------沃茲基-碩德

人生最大的喜悅是每個人都說你做不到,而你卻做成了它                                     -----------wjm

僅憑閱讀本文,您必然不可能搭建出流水線CPU,但是,您的收獲可能有:了解實現CPU時的一些細節;知道教程中講的一些東西用人話怎么說明白,通過一些實例深入理解教程,糾正自己對於流水線CPU的一點誤解;知道如何去手動造數據、通過其他途徑獲得測試數據和debug思路,知道課上測試可能考察的一些指令的類型以及實現方法。

沒錯,像P3P4一樣,我又遭遇了重寫風波+自然死亡。

為何重寫?一是第一版搭建時間過於長了,從剛開P5,到前天,我一直都是在忙着設計和修改第一版,由於一些基礎概念沒弄明白,教程中有一些東西沒看懂,設計思路支離破碎,主觀的加入了一些毫無必要的“優化”,端口命名和導線命名又犯了P4中出現的錯誤而變得十分麻煩,以至於mips頂層模塊端口極多,非常復雜,連線難度巨大。在debug過程中,更是發現自己只會使用假的單步調試法,而不會“單周期”調試法,所以遲遲無法發現自己的bug。在向lcy大佬和討論區諸多大佬的討教經驗之后,決定重新來過。至此,世界上多了一位重寫P5的愚者。還好,沒弄多久就造出來一個命名、接口個數、模塊封裝和連線都比較舒適的全新版流水線CPU。

2020/2/11更新

由於期末時時間太緊張+自己試驗進度屢屢受挫+考試更新后莫名沒保存上+寒假春訓進度推進太快,到現在才把坑給填上,在這里表示抱歉。

由於P6是在P5的基礎上進行的改造,幾乎只是規模上的擴大,基本實現方法是一樣的,所以本文筆者將P5和P6合在一起總結一下,且主要講P5。由於筆者的設計風格並不好,所以本文沒有給出具體的代碼實現,防止帶歪讀者,設計風格問題本文也沒有給出詳細的探討(其實這個問題很重要)。想了解的同學可以關注微信公眾號“心中有13樹”以及多多留意課程討論區,里面有很多關於設計風格的文章,值得一讀。

由於筆者水平實在有限,所以即使是筆者寫在文中感覺比較穩的部分,也難免有表達不當甚至理解不到位之處,還請各位在評論區批評指正。

P5的要求是我們要用verilog實現一個流水線CPU,支持10條指令(和P4似乎就差一個jalr跳轉指令),P6是支持50條指令。

P5相對於P4絕對是難度上的飛升,一個原因是P5實驗開始時,可能很多老師的理論課還沒有講到或者沒有講完流水線部分,所以如果自己屬於進度最快的那批的話,就得盡快理解流水線CPU的工作機制以及暫停轉發的原理,這一點是困難的;另一個原因,是我們要求的流水線CPU必須是全速轉發的,也就是說,能不暫停就盡量不暫停(比如lw后面加計算指令沖突的就是必須要暫停的,而兩個計算指令沖突則是可以全速轉發避免暫停的),這就導致了我們不能用無腦5周期暫停法去實現它(不過在課上測試的時候實在不會寫轉發可以用5周期暫停法委曲求全,數據如果良心的話有概率過),所以轉發機制就會相當地復雜,思考量和代碼量刷的一下子就上來了,最后好不容易寫出來了也很難去遍歷所有可能的沖突情況去構造測試樣例。即使P5再困難,我們也必須去克服它,不然這門課就掛科了(滑稽)。

鑒於本實驗難度確實較大,所以在搭建P5CPU之前,請確保自己學了(不一定是學會)流水線CPU的相關內容(參考課件或者黑書都是可以的),會分析典型的數據冒險;確保自己在仿真時能夠正確地使用工具進行高效的debug;確保自己研讀過高老板的工程化方法的課件……有了上述知識,我們就可以考慮進行試驗了。筆者這篇文章意在把教程以及課件中一些不是人話的東西翻譯成人話,以便於理解。理解能力較強的大可自己放手看課件與教程去做。如果確認要閱讀此文,也請先夯實流水線理論課知識以及至少瀏覽一遍工程化方法教程。

為了方便各位正確理解筆者在說什么,先放一張自己對於流水線CPU的分級圖:

 

 

 以下討論基於這張圖里的命名,即僅說一個字母時代表兩級流水線寄存器之間的部分,兩個字母連起來是代表對應位置的流水線寄存器。可能與有些讀者的習慣不太一樣,所以請按照本命名閱讀文章之后再翻譯成您所習慣的命名方式。

首先,我們需要進行數據通路的設計,在這里,我們仍然需要使用在P4中使用過的列表的方法,在不考慮控制單元以及任何冒險的情況下,把各個指令的數據通路列出來,建議用excel表格。表格的格式,請參考工程化方法課件。與P4不同的是,我們這里將流水線分為了F,D,E,M,W這5級,並且每兩級之間要用流水線寄存器分隔開。注意GRF的特殊性(物理上是1個,邏輯上是2個),要考慮好回寫數據的來源。注意D級的各種小部件,這些和控制冒險有關。關於流水線寄存器,它並不是什么很玄的東西,其實就是定義若干的register,當時鍾上升沿來了的時候將數據寫入register而已。流水線寄存器在表格中寫起來的困難之處在於,由於以后我們還要加轉發,所以我們一下子想不清楚要把哪些必要的值傳下去。如果糾結於這個問題,我推薦大家先不要花費太多時間空想,現在就暫時只把它作為單周期的時候用到什么值傳下去就好了,千萬別在這個時候就糾結轉發相關的問題,不然進度會非常慢(比如筆者就由於太糾結轉發,用了一天多才填完數據通路表,沒寫一行代碼)。有必要說的是,各位在列表格的時候,仔細考慮一下接口命名,良好的命名能夠在P5中發揮巨大的作用,少出很多奇怪的連線bug。事實上,接口問題是P5的一個很重要的問題。很多時候我們會因為不知道接口需要有哪些,而不能理解我們為啥要造這么一個模塊。只有分析好了接口,我們才能有的放矢的去實現功能。如果實在想不好怎么命名,可以參考一下學長學姐的命名,不建議采用高老板課件中的命名。

基本的插入流水線寄存器的數據通路大表格寫好之后,考慮控制器。事實上,如果使用分布式譯碼(每個流水級有專屬的控制器)的話,P5和P4的控制器基本一樣,可以把P4的復制粘貼一下,大家看缺哪條指令就把哪條指令加進去,把控制信號加進去就行了。考慮到P5之后的任務都是在P5上擴展,所以控制信號(比如ALU的選擇計算功能的那個信號)位數可以多一點,5位肯定夠用,4位的話就得看個人設計情況了,有的人夠有的人不夠。注意,在頂層中,每級流水線不會用到控制器的所有接口,所以沒用到的那些就不要在頂層寫出來了,不然導線多得能煩死。當然,除了分布式,大家也可以考慮集中式譯碼,由於筆者沒有嘗試過,所有對集中式譯碼不做過多評論。

接下來就是P5最難的部分:沖突單元設計。在設計沖突單元之前,我們仍然需要先列一個表格,表格的內容是各種指令(更本質的來講,是各類指令)在不同級時可能出現的數據冒險。在這里,我使用的是教程中的Tuse和Tnew分析法。重點再強調一下,Tuse是當某條指令還在D級(也就是還沒寫入DE級流水線寄存器的時候)時,至少再等多少個周期(也可以說是還得再來幾個上升沿)就必須用到數據,Tnew是當某條能寫入數據的指令,再過多少個周期才能產生最新數據(此處的產生是已經寫入到流水線寄存器,如果只是剛算出來還沒寫入流水線寄存器的話我們不認為是產生,原因考慮時鍾周期)當Tuse>=Tnew時,是可以來得及轉發的;當Tuse<Tnew時,是來不及轉發的,必須暫停。如果考慮不明白這個方法的原理以及這個結論的話,請大家仔細思考我們理論課中所說的“數據必須在時鍾沿來之前准備好”這句話。如果大家在這里真的遇到了理解上的困難,希望大家能向老師或者大佬請教,請他們用一兩條典型的指令去手動給你模擬一下沖突產生原因以及轉發過程,這樣就不會死鑽牛角尖而沒有收獲了。至於表格的細節部分,請參考我們的教程部分以及高老板課件。

稍微再說一點有些多余但能讓大家更好地理解的東西:我們為啥要列這個表格?簡單來說,就是我們想知道什么時候暫停, 什么時候轉發,我從哪里轉發,我轉發到哪里。一旦我們判定了某個時候該轉發時,在實現上我們的做法是:生成一個控制信號,這個控制信號接到一個多路選擇器上,多路選擇器選擇我們要把哪個作為某個部件的輸入。比如我們可愛的ALU,它可能的數據來源是什么呢?D級從GRF中讀出來順着往下流水的,EM級流水線寄存器轉發回來的(連續計算指令導致),MW級流水線寄存器轉發回來的(load后加計算指令導致)等等。比如我們現在在D級正有指令addu,在E級正有指令subu,addu讀取的某一個寄存器和subu寫入的寄存器是同一個寄存器,發生數據冒險,並且可以分析addu的Tuse=1,subu的Tnew=1,所以我們可以通過轉發解決這個問題。當下一個時鍾上升沿來的時候,E級的計算結果寫入了EM級寄存器,D級的數據流入DE級流水線寄存器,並且進入了E級進行了計算,只不過它的結果還沒有被存儲(形象地說,ALU的計算結果正“頂”在EM級流水線寄存器的左端,但是它目前還沒頂進去)。這個時候,我們在ALU的兩個輸入端都加上多路選擇器。假如ALU下面那個輸入端口的是EM級流水線寄存器結果需要到達的目的地,我們就讓這個結果連到ALU下面的端口對應的多選器上,並且產生一個選擇EM流水線寄存器轉發結果(而不是D級流水數據或是MW轉發數據)的信號,這樣ALU就是使用正確的值在運算了。由於E級本身是個組合邏輯,所以在轉發之后它最終穩定的結果是正確的。當下一個時鍾上升沿來的時候,這個正確結果就流水下去了,我們轉發的目的就達成了。相信我這樣說了之后,大家就更能理解轉發機制的工作了。其他的轉發情況的分析與實現是類似的,請大家仿照例子自行思考。暫停比較簡單,可以完全參考課件,注意暫停時清空哪些寄存器。

 上一段文字中提到了我們選擇轉發數據的多路選擇器,這些多路選擇器的控制信號就是多種多樣的轉發信號了。為了設計這些多選器,我們也需要列表格去分析多選器可能會有哪些數據來源(比如剛才說的ALU輸入端的多選器的可能來源)。這個部分請大家參照高老板課件,多路選擇器命名也可以參考高老板的命名方法(MFRSD,MFRSE等等)。

怎么轉發可能大家已經都知道了,那么,如何實現檢測沖突呢?我們先想一想沖突的原因:要寫的寄存器和下面一條指令要讀的寄存器是同一個。所以,我們可以匯總每一級中的要寫的寄存器和要讀的寄存器(rs,rt,rd),將它們作為沖突單元的輸入,然后在沖突單元中把所有可能的沖突都列舉一遍並生成相應的多選器信號就好了。在這里列舉時我使用的暴力轉發法,各位可以在教程中自行學習,暴轉思路真的很流暢!

控制冒險?注意D級各種小部件的實現,注意延遲槽。參考課件

到這里,當我們寫完了各個流水級的模塊代碼,寫完流水線寄存器的代碼,寫完沖突單元的代碼,寫完多選器們的代碼,以及copy完P4的控制器代碼,這個CPU的所有單元就都有了,只需要在頂層進行連線就可以了。在這里,我們推薦把每個流水級的模塊打包成一個整體模塊,比如我們可能取址級有一些PC+4和多選器之類的小東西,統統封裝為F模塊,這樣可以減少頂層連線。當封裝完畢,連線也完畢之后,可以說流水線CPU就搭過了。接下來就是測試與debug了。

如何測試呢?先提一句,評測機是不夠的,即使是所謂的中強測,也是很不完備的,我們仍需要構造更全面的樣例進行測試。首先是進行功能測試,測試每條指令執行結果對不對。在這里,大家可以在測試代碼中每一條指令就后面跟上5個nop,這樣保證無沖突。功能測試能測出來很多明顯的sb連線錯誤。在功能測試沒問題之后,就是進行暫停轉發測試了。在這里,筆者完全不贊同自己寫花里胡哨的一個測試程序去測,這樣根本測不全。那應該怎么測?先靜態debug:看好你的沖突單元,看看你枚舉過的那些沖突類型,先靜態觀察一下是不是寫夠了,可以和同學們交流一下看看是不是寫夠所有情況了,要是漏了情況就肯定錯了。如果沒漏情況,我們開始造數據測試:把你列舉的每一種情況,都寫一段小程序去單獨地測沖突。比如E級寫回的rd寄存器與D級使用的rs寄存器的沖突,涉及到的指令(比如寫rd寄存器的addu,subu,以及P6時的很多計算指令balabala,讀rs寄存器的所有指令)我們都得分別地測沖突。在這里,大家就可以考慮優化自己的沖突單元,看看是不是可以將指令分類,這樣我們就可以按照指令種類從中選一個代表元而不是每個指令都得枚舉出來測沖突了(比如分成calculate_r,calculate_i,b,j,jal,jr,jalr,load,store這么幾種,過P6足夠)。手動生成測試樣例是很麻煩的,但是為了覆蓋性測試,我們必須手動來一遍以保證全面性,等覆蓋完了,可以寫評測機或者借大佬寫的評測機再測幾千組數據。另外,關注過我寫過的其他文章的讀者可能還知道6系流傳着P5的一份覆蓋性很好的測試數據 ,大家也可以找一下那套數據進行測試。但為了大家真正學到東西,希望大家能自己先手動造數據,然后再通過其他數據來提高自己CPU的“置信度”。不然的話,即使過了P5,你也可能因為自己沒有手動造數據這個過程而在沒有現成的數據支撐的情況下掛掉本來應該白給的P6。自己寫測試用例生成器乃至評測機是可以的,不過你可能需要一些前置知識,可以參考我寫的某篇博客來初步了解(但我提供的遠遠不夠)。

通過以上講解,P5要求的流水線CPU就基本完成了,之后能不能過就看各位的本事了。關於P5,P6課上測試題型總結,請看這里:http://wechat.cscore.net.cn/thread/5ddff1d18ec6a61e4a00005f?message_id=276&code=n5SNjlDTiDmqfXrGHwNzitnlM8a4O3kmJXW2fRWpuWo&state=1&debug=False ,這里有較全的課上測試題型總結,非常有價值!感謝作者@18376176 

關於P6,乘除模塊以及DM擴展請看教程,注意Instruction memory不要再從0x3000開始了。P6主要是加指令,都比較好加,然后就是加入乘除之后的數據冒險。我們可以把乘除指令和ALU的一些計算指令一起處理,就可以幾乎不改動沖突單元了。其實P6大家可以多看看應屆討論區,里面的內容應該會更好更有針對性。要想寫得漂亮,加指令的時候改動少,那么就得注意自己的設計風格。請大家留意設計風格之planner VS detector,選擇適合自己的將代碼進行優化,防止自己課上手忙腳亂出錯。

最后,希望大家能夠AKP5 && P6,沖向P7P8。筆者由於只通過了P6,所以只能分享到這兒了。願大家都能在計組中揮灑汗水與淚水,收獲成功的喜悅!奧利給!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM