999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

芯片敏捷開發實踐:標簽化RISC-V

2019-02-20 03:38:04余子濠劉志剛李一葦黃博文孫凝暉包云崗
計算機研究與發展 2019年1期
關鍵詞:設計

余子濠 劉志剛 李一葦 黃博文 王 卅 孫凝暉 包云崗

1(計算機體系結構國家重點實驗室(中國科學院計算技術研究所) 北京 100190)2(中國科學院大學 北京 100049)

芯片是信息技術的引擎,推動著人類社會的數字化、信息化與智能化.隨著摩爾定律瀕臨終結,維持芯片技術創新面臨挑戰.開源芯片設計將是應對挑戰的新思路.

如今芯片設計動輒需要上億研發費用、投入上百人年,而一旦流片失敗,將會浪費巨大的成本,只有少數企業才能承擔相應的風險[1].反觀互聯網領域通過開源軟件降低開發門檻,創造了繁榮的互聯網產業.如果開源芯片設計能實現敏捷開發,將芯片設計門檻降低幾個數量級——3~5人的小團隊在3~4個月內,只需幾萬元便能研制出一款有市場競爭力的芯片,就可以大大降低芯片開發的成本和風險,必將吸引大量人員投入芯片產業,重塑繁榮.

加州大學伯克利分校設計的開放指令集RISC-V[2]朝著這個目標邁出了第1步,它有望像開源軟件生態中的操作系統Linux那樣,成為計算機芯片與系統創新的基石.但為了實現芯片的敏捷開發,只有RISC-V是遠遠不夠的,還需要一個能夠經過流片驗證的RISC-V SoC開源設計,以及一門面向敏捷開發的硬件構建語言[3].因此在推廣RISC-V的同時,伯克利研究團隊也開放了RISC-V的SoC實現Rocket Chip[4-5],以及面向敏捷開發的硬件構建語言Chisel[6],期望通過這三駕馬車率領芯片設計領域邁進敏捷開發的時代[注]RISC-V和Chisel是由伯克利中2個不同的團隊分別設計的.

本文希望探索這樣一個問題:RISC-V,Rocket Chip和Chisel是如何推動芯片敏捷開發的?為了探討這個問題,我們將探討3個方面的內容.

1) RISC-V和Rocket Chip如何降低芯片開發的門檻?為了探索這個問題,我們介紹了RISC-V的開源開放理念,同時以中國科學院計算技術研究所開展的標簽化 RISC-V[7-8](Labeled RISC-V)研究項目為案例,分別從設計開源度、定制靈活性、生態完整性以及社區活躍度4個方面,把開放不活躍的SPARC V9[9]、活躍不開放的MicroBlaze[10],與開放又活躍的RISC-V進行對比,揭示了一款不開放或者不活躍的指令集對芯片設計項目帶來的限制,從而展示了RISC-V和Rocket Chip對降低芯片開發門檻的價值.

2) Chisel如何對項目的敏捷開發提供幫助?為了回答這個問題,我們分別介紹了Chisel的信號整體連接、元編程、面向對象編程以及函數式編程的特性.同時我們以標簽化RISC-V中的項目經驗為例子,展現了這些特性如何幫助我們快速地開發項目需要的功能,并將這些特性與傳統的硬件描述語言,包括Verilog[11]和SystemVerilog[12]進行比較,展示Chisel代碼的簡潔性、易讀性以及易維護性,從而對項目的敏捷開發提供幫助.

3) 敏捷開發和傳統開發相比,編碼的效率和質量怎么樣?為了展現2種開發模式的效率對比,我們分別使用2種模式來開發一個功能相同的二級緩存(L2 cache)模塊.結果顯示:與傳統開發模式相比,敏捷開發模式的開發效率提升了一個數量級,同時編寫出的代碼可讀性更好,更容易排除錯誤.為了展示2種開發模式的質量對比,進一步屏蔽設計的差異,我們將采用傳統開發模式的Verilog代碼翻譯成功能相同的Chisel代碼,并在FPGA流程上對翻譯前后代碼的性能、功耗、面積進行評估.結果顯示:敏捷開發能達到與傳統開發相當甚至更優的編碼質量.

1 開放指令集的理念

2010年,伯克利研究團隊準備為接下來的一系列項目選擇一款指令集.結合項目的需求,他們最后決定在x86和ARM中進行選擇.但是選擇x86是不可能的,首先它有知識產權問題,而且設計非常復雜.但ARM也是幾乎不可能,它不僅和x86有同樣的問題,而且當時并沒有64位指令集的規范.這讓伯克利研究團隊感到困擾.

他們對當時指令集的狀況進行了一些調研,發現即使是一個小小的SoC芯片,里面也包含很多處理器,包括應用處理器、圖形處理器、圖像處理器、視頻DSP、音頻DSP等.但是這些大大小小的處理器使用的指令集可能都各不相同,比如應用處理器一般用ARM指令集,從不同廠商購買的IP核也許都會用自己私有的指令集,就連SoC廠商自己設計的核心,也可能會用自己的指令集.而這些都位于同一顆SoC芯片上的各種核心,都有自己獨立的一套軟件棧.

但是,我們真的需要這么多不同的指令集嗎?為了回答這個問題,伯克利研究團隊又調研了開源軟件的狀況,發現和指令集的情況大不相同.如表1所示,開源軟件中的不同領域,都有一套開放的標準,在這套開放的標準之下,既有開放自由的實現,也有私有的實現.雖然總體上私有實現的效果更優,但開放自由的社區也非常活躍.然而,以私有實現主導的指令集領域卻毫無生機.

Table 1 Summary of Open Software Standards表1 開放軟件和標準小結[13]

如果有一款開放自由的指令集,大家都可以用它來做任何事情,會怎么樣呢?借鑒軟件領域的發展狀況,伯克利研究團隊認為,指令集體系結構作為軟硬件接口的一種標準,不應該像x86和ARM等指令集那樣需要授權才能使用,而應該開放(open)出來讓大家自由(free)使用,這樣才能塑造指令集領域的繁榮生態[14].于是伯克利研究團隊發起了一個持續3個月的暑期項目,目標是從零開始設計一款新的指令集,并將其徹底開放.

這套新的指令集被命名為RISC-V(讀作RISC-Five).2011年5月第1版RISC-V指令集正式發布.

實際上,第1版RISC-V發布后并未受到關注,也未取得預期反響,反而備受多方質疑.一方面,很多學術界人士認為RISC-V指令集毫無技術創新;另一方面,工業界對于這種由學術界推出的新指令集也是持觀望態度.開放指令集的理念和意義并未得到廣泛認可.

面對各方質疑,伯克利研究團隊采取了3項措施:

1) 研究團隊設計并實現了一個基于RISC-V指令集的順序執行64位處理器核心(代號為Rocket),并對相應的SoC設計Rocket Chip進行開源.隨后伯克利研究團隊又推出了開源的亂序執行核心BOOM(Berkeley out-of-order machine)[15-16].這兩款開源的微結構設計打破了學術界長期缺乏可用芯片原型的困境,很快吸引了學術界的廣泛關注.

2) 伯克利研究團隊在2015年成立非盈利組織RISC-V基金會(RISC-V Foundation),旨在凝聚全世界的力量一起共同構建開放、合作的軟硬件社區,打造RISC-V生態系統.

3) 伯克利研究團隊從2015年開始組織舉辦RISC-V技術研討會,鼓勵企業和科研機構在研討會上分享RISC-V相關的工作和研究,從而傳播RISC-V開放指令集的理念和意義,大大地加深了人們對RISC-V的了解[17].

伯克利研究團隊實施的這一套組合拳,很快讓RISC-V成長為一個開放又活躍的社區.

2 標簽化RISC-V項目中的指令集選擇

關于RISC-V開源開放的理念對學術研究的意義,我們在開展標簽化體系結構這一科研項目的過程中也深有體會.標簽化RISC-V是一個基于RISC-V指令集的標簽化體系結構的實現,它基于RISC-V指令集的開源實現Rocket Chip,添加了標簽化體系結構相關的功能.標簽化體系結構的主要思想是通過標簽向底層硬件傳播軟件信息,向硬件添加身份識別、區分服務、性能調控等新功能.標簽化體系結構有4點特性[18]:

1) 細粒度對象.所有訪存和I/O請求都帶上標簽.

2) 語義關聯.標簽和軟件實體(包括虛擬機、進程、線程或變量)進行關聯.

3) 攜帶傳播.標簽隨著請求一同在整個系統中傳播.

4) 可編程控制邏輯.對攜帶不同標簽的不同請求進行區分化處理.

基于這些特性,標簽化體系結構的其中一個應用場景,是保證關鍵應用性能的同時,提高系統的資源利用率[19].具體地,我們可以通過標簽向底層硬件傳遞訪存和I/O請求的身份信息,這一身份信息會隨著請求在整個系統中傳播.這樣以后,硬件共享資源的控制器(如末級緩存控制器、內存控制器等)就可以識別收到的一個請求來源于哪個應用,若發現請求來源于關鍵應用,則優先對其進行處理,并保證其使用的資源不受非關鍵應用的干擾;若發現請求來源于非關鍵應用,則對其提供盡力而為的服務.

原則上,標簽化體系結構可以實現在任意一款指令集之上.在項目前期,我們也曾經在多款指令集中進行選擇和嘗試,最終體會到RISC-V的開放活躍對學術研究的意義.

2.1 開放不活躍的SPARC V9

我們一開始在2013年7月選擇了OpenSPARC T1[20]來開展項目.它是一個8核32線程的64位工業級微結構實現,采用SPARC V9指令集,在2006年通過GPL協議開源.我們本來以為這款工業級的開源實現可以給項目帶來性能上的保障,但是在開展過程中,我們遇到了4個挑戰:

1) 工具不再維護,所依賴的庫版本較老,難以尋找與其適配的開發環境;

2) 缺少詳細設計文檔,工程中注釋較少,閱讀并理解工程中的Verilog代碼較為困難;

3) 生態不完善,難以運行真實應用;

4) 社區不再活躍,難以尋求幫助.

我們原計劃將OpenSPARC T1的實現從8核32線程裁剪為單核單線程,再開展標簽化的研究.但由于上述挑戰,裁剪的定制工作非常困難,進行了約半年時間卻未有明顯進展,最后無奈放棄OpenSPARC T1這款開源設計.這說明,只開放但不活躍的指令集,雖然能讓研究者使用,但定制的難度很高,要基于一個不活躍指令集開展項目研究還是很困難.

2.2 活躍不開放的MicroBlaze

之后我們嘗試了賽靈思(Xilinx)的MicroBlaze架構,它是一款主要面向嵌入式領域的處理器.與OpenSPARC T1相比,MicroBlaze的微結構設計、生態和社區都由賽靈思維護.2009年6月,MicroBlaze作為第1款軟核CPU架構并入Linux內核主線;3個月后,MicroBlaze的GNU工具鏈也開始并入相應的主線倉庫[21]并一直在演進,而GCC則從4.6發行版開始支持MicroBlaze[22].在賽靈思論壇的MicroBlaze板塊,開發者踴躍提問,并且能很快得到賽靈思工作人員的答復.這表明,MicroBlaze的生態和社區狀況非常健康,這也是我們項目選擇MicroBlaze的一個重要原因.

我們雖然在開發過程中也會遇到困難,但借助社區的力量,我們很快就解決了困難,構建出一套可以運行Linux的系統.然后我們在MicroBlaze上進行了4個方面的擴展,實現了標簽化體系結構:

1) 細粒度對象.在核外添加標簽寄存器.

2) 語義關聯.標簽寄存器中存放虛擬機的標識.

3) 攜帶傳播.把標簽寄存器中存放的標簽連接到AXI總線的USER域中,通過AXI總線將標簽傳播到整個系統中.

4) 可編程控制邏輯.向賽靈思系統緩存(Xilinx system cache[23])模塊的替換算法添加基于標簽路劃分的功能,并添加可編程的緩存控制邏輯模塊,對路劃分的參數進行編程,來實現緩存容量的隔離;同時在內存控制器前的數據通路中添加基于標簽的令牌桶模塊,并添加可編程的內存控制邏輯模塊,對令牌桶的參數進行編程,來實現內存帶寬的隔離.

雖然我們成功在MicroBlaze上實現了標簽化體系結構,但在實現過程中,我們仍然遇到了表2中的困難.

Table 2 Summary of Challenges About MicroBlaze表2 使用MicroBlaze的挑戰總結

表2中,第1種困難屬于模塊復雜度較高,同時缺少相關資料幫助理解該模塊的細節.例如賽靈思系統緩存模塊的代碼約6萬行,我們需要在其中添加基于標簽路劃分的替換算法,但由于缺少詳細設計文檔和注釋,理解代碼較為困難.這種困難可以通過投入足夠時間來克服.我們安排了一位工程師專門閱讀賽靈思系統緩存模塊的代碼,花費了將近半年時間才完成替換算法的添加,雖然最終成功實現這一功能,但這也一定程度上也影響了從想法到原型的周期(time to prototype).

第2種困難是代碼不開源帶來的限制,雖然對工程實現有一定影響,但可付出少量代價繞開.例如AXI數據寬度轉換器會截斷USER域[24],導致基于USER域實現的標簽無法繼續往后傳播.但由于相關代碼不開源,我們無法修改轉換器的代碼,只能在項目中小心地規劃模塊的順序,避免在標簽傳播的通路上使用這個轉換器;在必須使用轉換器的情況下,只能額外將標簽接入到轉換器的下游模塊中來讓標簽繼續傳播.另一個例子是由于MicroBlaze處理器不開源,我們無法在處理器內部添加寄存器來實現進程級標簽,只能把標簽寄存器放置在處理器外面,讓操作系統通過I/O的方式來設置進程級標簽.雖然這個解決方案會帶來一定的性能開銷,但至少繞開了無法修改處理器的限制.

第3種困難同樣是代碼不開源帶來的限制,雖然沒有解決方案,但相關的研究工作還是可以繼續開展.例如MicroBlaze處理器主要面向嵌入式場景,性能一般.我們在測試后發現,在運行云計算典型應用(如Memcached)時,軟件管理的TLB在缺頁頻繁時帶來了約20%的性能開銷,但由于處理器代碼不開源,我們無法對相關設計進行改進.不過對于我們的項目來說,這一性能開銷還是可以接受.

第4種困難也是代碼不開源帶來的限制,但卻無法解決,會直接限制相關研究工作無法開展.例如MicroBlaze無法運行多核操作系統,這是因為為了運行多核操作系統,我們需要一種多核核間通信的方式,例如核間中斷(inter-processor interrupt, IPI),還需要一種內存同步和通信的方式.要實現這些功能,就需要對處理器內部進行改動[25],但由于處理器代碼不開源,我們無法對其進行改進,使其支持多核操作系統.另一個例子是流片,不開源的處理器自然也無法流片.

因此,不開放的指令集和微結構實現,會對相關研究工作在項目周期、工程實現和性能表現等方面帶來頗多影響,甚至會使得部分顛覆式前沿研究無法開展.為了解決這些問題,就需要有一款開放的指令集以及相應的開源微結構實現.

2.3 開放又活躍的RISC-V

有了SPARC V9和MicroBlaze的經歷,我們意識到需要有一個開放又活躍的指令集來支撐項目的開展.事實上,期間我們還因為ARM的活躍社區和生態而調研過基于ARM的解決方案,然而ARM的開放性比MicroBlaze還弱,而且需要支付高額的授權費用,一般的研究項目無法承擔,最終還是放棄了ARM的選擇.最后我們選擇了RISC-V,依托其開放的理念及活躍的生態,在其微結構實現Rocket Chip上成功解決了在MicroBlaze上遇到的問題:

1) 實現簡單.Rocket Chip的二級緩存模塊代碼約1 000行,即使缺少詳細設計文檔和注釋,我們花費約3天時間就成功實現了之前在賽靈思系統緩存上實現的功能,效率提高了50倍.

2) 修改靈活.我們通過Rocket Chip上使用的開放總線協議TileLink[26]來傳播標簽,我們在TileLink總線上靈活地添加一組信號來專門傳播標簽,在TileLink總線適配器(如數據寬度轉換器等)不能自動傳播標簽時,可以靈活地修改適配器的硬件代碼來實現標簽的傳播;此外,我們可以靈活地在Rocket核心中添加一個新的控制狀態寄存器(control status register, CSR)來存放進程級標簽的信息,操作系統可以通過CSR指令高效地進行設置.

3) 性能較高.RISC-V的TLB為硬件管理,性能比MicroBlaze高,而且若性能不能滿足項目需要,可以對處理器自由進行修改.

4) 支持多核.RISC-V豐富的生態已經支持多核操作系統的運行.

5) 允許流片.Rocket Chip的代碼全部開源,RISC-V也無需授權費用,可以進行流片.

表3總結了我們項目對不同指令集進行的嘗試.其中,基于SPARC V9指令集的OpenSPARC T1的微結構設計雖然開源,但由于代碼難以閱讀,對設計進行定制化非常困難,而且軟件生態的支持非常有限,社區也不活躍,對科研項目來說難以使用.MicroBlaze的生態和社區都由賽靈思進行維護,活躍度很好,但其設計不開源,只能對其進行很有限的配置,雖然總體上能滿足一些嵌入式研究工作的需求,但對于性能要求更高或者對芯片有所創新的研究工作,MicroBlaze還是難以勝任.RISC-V則結合了兩者的優點,首先開放的理念吸引了大批企業和個人幫助其建設生態,社區非常活躍;其次RISC-V有一款開源的微結構設計Rocket Chip,無論是指令集的模塊化,還是微結構的設計細節,大家都可以根據各自的需求對其進行靈活的個性化定制,而且可以直接將設計進行流片.

Table 3 Summary of Different ISA表3 不同ISA的特點總結

正是這些好處給芯片相關的科研工作帶來了很多嶄新的機會:與模擬器相比,在一個可綜合的平臺上進行驗證的工作將會更有說服力,同時距離真正芯片的實現也更近;而對工業界來說,這些好處也同樣受到青睞.因此,開放活躍的指令集和相應開源的微結構設計,是邁向開源芯片設計的第1步.

3 基于Chisel的敏捷開發

在學術界,目前大多數微結構相關的研究還是在模擬器上進行,這是因為基于FPGA的工作周期一般都比較長,例如我們的標簽化RISC-V研究需要花費約半年的時間來完成FPGA原型系統的構建,基于真實芯片設計的研究工作則鮮有聽聞.在工業界,芯片的開發周期長達2~3年,其中設計和驗證工作需要花費1~2年,投片需要花費約1年.如果流片失敗,投入的時間和精力將會付諸東流,風險相當大[1].因此,如果有辦法加快芯片設計的效率,實現芯片的敏捷開發,那么將會對學術研究和芯片產業帶來巨大的影響.

伯克利的另一個研究團隊在2010年的時候已經考慮到這方面的問題了,他們在2012年的DAC會議上發表了一門新的編程語言Chisel[6]來進行硬件的敏捷開發.Chisel的主要目標是減少項目中的重復代碼,提高代碼密度,從而提升開發效率、代碼的可讀性和易維護性.編寫Chisel代碼后,用Chisel編譯器將其編譯成底層的Verilog代碼(網表),可用于標準的ASIC和FPGA流程.需要說明的是,雖然Chisel支持傳統硬件描述語言不具備的很多高級特性,但Chisel還是一門硬件構建語言,而不是高層次綜合語言.硬件構建語言用于描述電路具體如何構建,而高層次綜合則用于描述算法的流程.

3.1 信號整體連接

Chisel豐富的類型系統使得我們可以很容易地修改類型的定義,在不修改引用該類型的代碼(如通過該類型來定義的信號)的情況下,可以輕松對該類型的信號進行全局修改.此外,整體連接運算符“”會根據類型的定義,把相同類型的2組信號的相應成員信號一一連接,從而省去重復而且易出錯的連線代碼.在工程項目中,我們一般會在代碼中的不同位置定義同種類型的信號,比如總線信號.在這種情況下,信號整體連接的特性能大幅減少項目中的重復代碼.

在標簽化RISC-V項目中,為了在TileLink總線上添加標簽并實現攜帶傳播,我們只需要添加4行Chisel代碼.圖1中以“+”為行首的代碼為添加的代碼.具體地,添加的代碼首先定義一個寬度為tlDsidBits的新信號dsid,然后把這個新信號加入到TileLink協議的元數據中.在類型系統的作用下,項目中定義的所有TileLink總線都會自動帶上這個新成員信號dsid.此外,由于項目中使用“”來連接TileLink總線,因此“”也會自動將新成員信號dsid連接起來.我們無需編寫額外的代碼,就已經實現了標簽在TileLink總線上的攜帶傳播了.

Fig. 1 Implemention of labels over TileLink圖1 在TileLink總線上添加標簽的代碼實現

這個例子展示了敏捷開發中的一個常見現象:需求變更時,可以對項目快速進行修改以實現新的需求.使用Verilog語言進行開發時,若要對總線的成員信號進行改動,工程師只能對項目中所有用到總線的模塊端口逐一進行改動,同時還需要手工添加或移除相應成員信號的assign語句,這對Verilog工程師來說是一件非常麻煩的事情.SystemVerilog的interface特性一定程度上也能實現類似Chisel中信號整體連接的功能,但它仍然有一些局限性,例如modport不能嵌套定義,使得我們無法從不同的interface中將相同的部分進一步抽象出來.Chisel中的信號整體連接特性比SystemVerilog還要強大,這使得我們可以進一步減少重復的代碼,實現“一改全改”的效果,從而提升項目的開發效率.

3.2 元編程

Chisel支持基于Scala的元編程,可以借助Scala的特性抽象出多份相似的Chisel代碼的共性部分,我們只需要維護一份共性代碼,具體的Chisel代碼可以通過對共性代碼實例化得到,從而進一步減少冗余的代碼.一個常見的例子是使用模板來實現隊列原型.無論隊列中的元素是何種類型,隊列本身的功能都是一樣的.使用模板可以將隊列本身的功能抽象成一個帶類型參數的隊列原型,然后在實例化時給出隊列元素類型就可以得到一個該種元素類型的隊列.通過這種方式,我們不必分別實現不同元素類型的隊列,只需要維護一份隊列原型即可.

圖2展示了Chisel使用模板類Queue來抽象出隊列原型的一個例子.行①表示這個模板類接收隊列元素gen和隊列項數entries兩個參數,其中隊列元素類型并未事先確定.行②定義模塊的輸入輸出端口.行③定義隊列的存儲單元,它們均與隊列元素類型有關.行④和行⑤分別定義隊列的讀寫指針.剩余代碼未列出,但其實現與傳統硬件描述語言非常類似.有了Queue模板類,我們就可以通過它來定義各種元素類型的隊列了.

Fig. 2 Example of template class in Chisel
圖2 Chisel模板類例子

在標簽化RISC-V項目中,在TileLink總線中添加標簽之后,一個需要考慮的問題是,項目中有一些對TileLink請求進行緩沖的隊列.我們希望標簽能夠隨著請求一同經過隊列,以實現攜帶傳播的效果,這也許要求我們修改相關的代碼.幸運的是,元編程的功能已經自動實現了這一效果.這是因為我們通過擴充TileLink元數據類型的方式加入標簽,本質上修改了TileLink類型,但上述隊列原型可適用于各種元素類型,從而無需修改相關的代碼.而為了在Verilog中實現這一功能, 針對代碼中的所有相關隊列,我們要么增加隊列元素的寬度,要么增加一個新隊列來專門對標簽進行緩沖,同時還需要維護標簽和請求的對應關系,十分繁瑣.SystemVerilog也支持模板,但相應的代碼是不可綜合的,更多的是用在測試激勵的編寫中.

3.3 面向對象編程

Chisel可以使用面向對象編程的特性來提高硬件開發的效率,在這里我們介紹繼承和重載.

3.3.1 繼 承

面向對象編程中的繼承特性允許我們將一些共同的代碼特性通過一個父類抽象出來,達到減少冗余代碼的效果,同時層次化的類型系統還可以使類型檢查的過程更加嚴格,從而降低代碼出錯的可能性.具體地,我們在實現一個模塊時,只需要從父類繼承,就可以讓該模塊自動擁有父類定義的所有特性,從而避免在不同的模塊中重復實現這些特性.

在硬件項目中,不少模塊之間都有一些共同的特性,例如cache的不同替換算法都需要讀出并更新歷史狀態,而對于帶有總線接口的模塊,總線相關的參數也非常相似.在這些情況下,使用繼承特性可以有效地節省項目的代碼量.

在標簽化RISC-V項目中,我們需要編寫一個生成隨機地址的TileLink負載發生器,來對基于標簽的令牌桶模塊進行壓力測試.圖3展示了該負載發生器的Chisel實現.其中,行[注]實際上是diplomacy[28]語言的功能定義了模塊的名稱TileLinkTrafficGenerator,它從TLModule類繼承.行②~⑤定義了該模塊的輸入輸出端口,包括一組TileLink主端口out以及一個從令牌桶模塊傳過來的使能信號traffic_enable.模塊內部的具體實現未列出,但整個模塊的代碼量只有20行.

Fig. 3 Example of inheritance in Chisel
圖3 Chisel繼承例子

從TLModule模塊繼承后,負載發生器模塊會自動擁有TLModule所擁有的所有特性,這些特性是具有TileLink接口的模塊所共同擁有的,包括總線的大量參數,如地址位寬、數據位寬等.這樣,我們就可以在行③通過1行Chisel代碼直接定義一個TileLink的主端口,而無需額外顯式指定大量的總線參數,讓代碼功能一目了然,容易維護.相比之下,傳統的硬件描述語言則難以實現類似的效果,例如若使用Verilog編寫,就需要40行代碼來聲明TileLink主端口,然后還需要編寫另外40行代碼對端口中的每一個信號進行賦值操作,加上模塊內部的具體實現,共需要約200行代碼來編寫此模塊,是Chisel代碼的10倍.在這種情況下,Verilog代碼就難以一目了然了.而SystemVerilog雖然支持繼承,但功能有限,而且相應的代碼不可綜合[27],無法對硬件構建提供幫助.

3.3.2 重 載

面向對象編程的另一個特性是重載,重載可以提升代碼的可讀性.首先,Chisel支持以函數的方式來對電路進行抽象(包括模塊實例化),以達到復用的效果,同時可以把函數返回值當做相應電路的輸出,直接作為Chisel表達式的一部分,而無需額外定義函數的輸出信號.此外,Chisel支持函數名重載,允許定義帶有不同參數的多個同名函數,而且可以設置缺省參數,在調用函數時,Chisel會在多個函數定義中自動選擇類型匹配的函數定義.運算符重載則是把運算符當作一個特殊的函數,可以根據運算符左右兩側的變量類型來決定運算符的具體行為.

在標簽化RISC-V項目中,我們需要在訪存通路上添加一個延遲器來凸顯二級緩存的效果,從而測試基于標簽的路劃分實現是否有效.圖4的陰影部分展示了新增的代碼.其中,原代碼通過函數AXI4RAM(),AXI4Buffer(),AXI4Fragmenter()和AXI4MasterNode(),分別實例化了AXI4接口的SRAM、緩沖器、分片器以及主節點,并將它們的AXI4主從端口依次連接起來.此處項目對運算符“∶=”進行了重載①,讓運算符兩側節點的AXI4主從端口通過“”進行整體連接.為了在通路上添加延遲器,我們只需要添加AXI4Delayer()的調用,來實例化一個延遲為150周期的延遲器,并通過重載后的“∶=”接入到訪存通路中,代碼功能一目了然,容易維護.相比之下,Verilog和SystemVerilog中的函數、任務和運算符均不支持重載,無法實現上述效果,只能使用module來實例化這些模塊,從而引入大量的連線代碼.

Fig. 4 Example of overloading in Chisel
圖4 Chisel重載例子

3.4 函數式編程

Chisel支持使用函數式編程的特性來描述電路,可以編寫更緊湊、可讀性更好的代碼.首先,Chisel使用“容器”(collection)來抽象電路元素,容器中可以是信號、寄存器、端口、模塊、映射等,或者是這些元素的復合.然后,Chisel使用map算子對容器中的對象進行批量操作,操作可以是連接、歸約、算術和邏輯運算、選擇、實例化、函數調用、計算新映射等,或者是這些操作的復合,操作結果返回一個新容器.通過容器和map算子的組合,我們可以輕松地通過少量代碼描述復雜電路.

在標簽化RISC-V項目中,我們需要把3.3.1節中介紹的負載發生器接入到Rocket Chip中,來測試標簽化令牌桶在極限情況下的效果,接入方式如圖5所示.具體地,我們希望在第2到n個核心的數據通路中分別添加一個2選1的TileLink crossbar,并接入相應的負載發生器,而第1個核心的數據通路則保持不變,從而達到讓n-1個負載發生器與第1個核心競爭L1toL2 Network模塊入口帶寬的效果.此外,我們還希望n是可配置的,取值可以是2,4,8等.

Fig. 5 Diagram of connecting traffic generators圖5 負載發生器連接示意圖

我們可以通過圖6所示的Chisel代碼實現這一功能.其中,行①的cachedPortsBeforeGenerator表示每個核心的TileLink主端口的集合,take(1)表示取出其中第1個核心的端口.行②的drop(1)表示取出除去第1個核心之外剩余其他核心(即第2到n個核心)的端口,map算子表示對這些端口迭代進行行③~⑨的操作.具體地,首先為每個端口取一個別名p(行③),行④實例化一個負載發生器模塊;行⑤將令牌桶的使能信號接入負載發生器;行⑥實例化一個2選1的TileLink crossbar;行⑦將迭代中的端口p和負載發生器模塊的主端口組織成一個列表,然后通過“”將2個端口分別接入到crossbar的2個輸入口;行⑧將crossbar的輸出口作為一次迭代操作的結果.這樣,行②~⑨的結果就是第2到n個核心的數據通路中crossbar的輸出口,連同第1個核心的端口構成的集合,取名為cachedPorts.行通過“”將cachedPorts接入到L1toL2 Network模塊中,就能實現圖5的效果.

Fig. 6 Example of functional programming in Chisel
圖6 Chisel函數式編程例子

這個例子說明了Chisel確實是一門硬件構建語言,而不是高層次綜合語言:容器中的對象和map算子的操作,都是可綜合電路中的概念.Chisel只是使用高級特性來方便地描述電路,而不是通過它們來描述算法.而Verilog雖然有for和generate特性,但它們只能基于整數進行迭代,與Chisel中可以對任意對象批量進行任意操作的功能相比,Verilog的迭代功能就非常有限了.例如上述例子在map算子中使用了“”運算符,能實現進一步減少重復代碼的效果,而Verilog和SystemVerilog均不支持函數式編程,難以實現類似效果.

3.5 開發語言對比小結

表4總結了Chisel和傳統的硬件描述語言(Verilog和SystemVerilog)之間的對比.Chisel支持信號整體連接,可以將類型相同的2組信號的相應成員信號自動連接起來;SystemVerilog的interface特性也可以實現類似的效果,但有一定的局限性,如modport不能嵌套定義;而Verilog則不支持此功能,其類型(wire和reg)不具備語義,因此只能逐個信號地定義和連接.Chisel支持元編程,包括模板類和模板函數,可以把功能近似但類型不同的類或函數進行抽象,進一步實現代碼重用的效果;System-Verilog也支持模板的部分功能,但相應代碼不可綜合,無法對硬件構建提供幫助,而Verilog則不支持模板.Chisel支持面向對象編程,通過繼承可以使子類自動帶上父類的特性,從而減少重復的代碼,層次化的類型系統也可以使類型檢查更加嚴格,降低代碼出錯的可能性,同時重載可以提升代碼的可讀性;SystemVerilog不支持重載,雖然支持繼承的部分功能,但和模板類似,相應的代碼是不可綜合的;而類型系統較弱的Verilog則完全不支持面向對象編程.Chisel還支持函數式編程,可以將任意電路對象作為容器的元素,并通過map算子對這些對象批量進行任意操作,從而實現用少量代碼描述復雜電路的效果;而SystemVerilog和Verilog均不支持函數式編程.

Table 4 Summary of Different Hardware Description Languages表4 不同硬件描述語言的特性總結

和傳統的硬件描述語言相比,Chisel的這些高級特性可以大大減少項目中的冗余代碼,提高項目的開發效率,同時高密度的代碼也提高了可讀性,使得項目更容易維護.正是Chisel語言的這些特性,使得它成為硬件敏捷開發的利器.

4 敏捷開發案例評估

我們將通過項目中的2個開發案例,分別從編碼效率(開發耗時和代碼量)和編碼質量(性能、功耗和面積)這2方面,對分別以Chisel和Verilog為代表的敏捷開發模式和傳統開發模式進行對比.

4.1 Chisel與Verilog編碼效率對比

我們團隊曾經由于項目需要,期望盡快實現一個簡單的共享二級緩存.該二級緩存無需實現一致性協議的功能,只需要具有緩存功能即可,但需要集成到標簽化RISC-V項目中并正確運行.團隊中的2人分別進行獨立開發,具體情況如表5所示.

參與開發的其中一位是團隊中的工程師,他在標簽化項目的早期閱讀并理解過OpenSPARC T1的二級緩存源代碼,也修改過賽靈思系統緩存,在其中成功添加基于標簽的路劃分功能,具有豐富的緩存設計經驗.這位工程師使用傳統開發模式,選擇Verilog語言來開發這個二級緩存,并決定從零開始搭建測試環境,不復用任何代碼.他主要開發了6周,編寫了約1 700行有效代碼.遺憾的是,截至本文投稿為止,他開發的二級緩存模塊仍然無法在標簽化RISC-V項目上成功運行.

Table 5 Case Study of Implementing an L2 Cache表5 L2 Cache開發案例對比

參與開發的另外一位人員是團隊中的大四本科實習生,他做過CPU課程設計,并有9個月的Chisel開發經驗,但從未設計過二級緩存.這位本科生使用敏捷開發模式,選擇Chisel語言來開發這個二級緩存,并使用Chisel標準庫來幫助設計,同時也復用標簽化RISC-V項目的測試環境.經過了2天的設計和仿真驗證,他就寫出了一個可以支持多核Linux啟動的二級緩存,有效代碼量約350行,只有工程師編寫代碼的1/5.不過這個二級緩存一開始并不支持不完整的突發讀寫,導致DMA模式的以太網模塊不能正確工作.一周后團隊將這個情況反饋給他,他又額外花了一天時間改動了約50行有效代碼[29],添加了對不完整突發讀寫的支持,并進行仿真驗證,最終成功支持DMA模式的以太網模塊正確工作.

這個案例充分展示了敏捷開發在項目中的優勢:運用語言的各種高級特性、復用標準庫中已經經過驗證的模塊來編寫易讀、易維護、高密度的代碼,可以大大提升項目開發的效率.具體在這個案例中,敏捷開發模式的效率是傳統開發模式的14倍!由于沒有進行代碼和環境的復用,這位工程師表示他花費了一半的時間在構建測試環境和編寫并測試基本元件(如RAM、隊列、仲裁器等)中,而使用Chisel的本科生并沒有在這些事情上花費任何時間.不過即使把工程師花費的一半時間排除在效率比較的范圍之外,敏捷開發模式的效率仍然是傳統開發模式的7倍.實際上代碼重用是敏捷開發的一個基本理念,代碼的重用率越高,項目開發的效率就越高.

有趣的是,這位工程師后來提到,當時為了編寫一份端口數量可配置的總線連接代碼,他在generate特性的基礎上運用了一些特殊技巧實現了這一功能,編寫了約250行Verilog代碼.但是工程師在編寫過程中,由于連線和數字下標太多,并且需要顧及總線握手協議,他曾經因疏忽而導致2個連線錯誤的bug,花了約3天時間才發現并修復它們.這位工程師還表示,這部分代碼的可讀性其實并不好,使用Verilog實現這一功能實在太繁瑣了,即使在代碼中有相應注釋,他在一周后也不能馬上理解他使用的特殊技巧是如何工作的了.相比之下,若使用Chisel來實現類似功能,我們只需要編寫2行代碼即可,可讀性好,而且幾乎不會出現錯誤.此外,本科生實際上也是在一周后重新回頭閱讀并修改自己編寫的二級緩存,但他仍然在一天內成功修復了問題,這說明代碼的可讀性對項目維護來說是非常重要的.

4.2 Chisel與Verilog編碼質量對比

考慮上述案例展示的2個設計,雖然它們的需求是一致的,但不同的開發人員可能會采用不同的實現方式,導致編碼質量的可比性不強.為了進一步對比Chisel和Verilog的編碼質量,我們找到團隊中的另一位沒有Chisel開發經驗的大四實習本科生,讓他來把上述Verilog代碼中的部分關鍵模塊翻譯成功能等價的Chisel代碼.我們在項目中提供了一些測試,用于驗證翻譯結果的等價性.

4.2.1 逐句翻譯

由于這位本科生一開始并沒有Chisel的開發經驗,他需要從零開始學習Chisel,并選擇最簡單的翻譯方式:逐句翻譯,而不使用Chisel的高級特性.這位本科生表示,他一開始覺得Chisel代碼比較難讀懂,但是學習并逐句翻譯Chisel代碼的過程中,他也逐漸感受到Chisel的方便之處,例如豐富的標準庫、方便的數據類型系統及其轉化機制、簡潔的時序邏輯編碼風格等,這些特性讓他對Chisel有了新的認識.

我們用Chisel編譯器把翻譯后的Chisel代碼編譯成Verilog代碼(網表),然后對其以及工程師編寫的Verilog代碼分別進行評估.我們在Vivado 2017.01中,使用xc7v2000tfhg1716-1型號的FPGA,在125 MHz的時鐘頻率下進行評估,結果如表6中第2,3列所示.為了評估設計的性能,我們展示了時序報告中的最差負時序余量(worst negative slack, WNS),并將其換算成可運行的最高時鐘頻率,結果顯示Verilog和Chisel最高分別可運行在135.814 MHz和136.388 MHz的時鐘頻率下,性能非常接近.而兩者的功耗則分別為0.770 W和0.749 W,和Verilog相比,Chisel的功耗節省了2.73%.而為了展示面積開銷,我們給出2份設計各自消耗的查找表(lookup table, LUT)和觸發器(flip-flop, FF)數量.我們對LUT的消耗分成邏輯和存儲2部分來統計,和Verilog代碼相比,Chisel代碼多消耗了13.14%的LUT邏輯,但節省了29.62%的LUT存儲,這是因為Chisel標準庫提供了RAM相關的基本元件,它與工程師實現的RAM被Vivado分別映射成RAM64M和RAM64X1D這2種不同的原語[30],其中RAM64M會消耗更多的LUT邏輯,但節約大量LUT存儲.對于FF,Chisel比Verilog節省了14.72%,這是因為Chisel編譯器對代碼進行了更進一步的優化.從代碼量上看,即使是逐句翻譯,Chisel也比Verilog節約了23.95%的代碼量,這是因為:1)和Verilog的generate特性相比,基于Scala的元編程特性編寫出的代碼更加緊湊;2)在Chisel中編寫時序邏輯無須像Verilog那樣聲明always塊;3)Chisel代碼不會產生鎖存器(latch),無須像Verilog那樣補全if和switch的所有分支.

Table 6 PPA and LoC Comparison of Chisel and Verilog表6 Chisel和Verilog的性能、功耗、面積和對比

逐句翻譯方式的整體評估結果說明,使用Chisel開發不但節省了代碼,編碼質量也和Verilog非常接近,在部分指標上甚至優于Verilog.

4.2.2 使用Chisel高級特性

這位本科生對Chisel上手之后,我們讓他使用Chisel的高級特性對代碼進行重構,包括使用Chisel標準庫來實例化RAM和隊列等基本元件,同時使用第3節提到的信號整體連接、元編程、面向對象編程和函數式編程來節省代碼量.在使用這些高級特性的過程中,這位本科生逐漸認識到Chisel的更多好處,他表示:使用Chisel標準庫之后,因為大部分異步通信被統一封裝為Decoupled模板類,為了能使用“”進行信號整體連接,自然就會嘗試從Bundle類繼承來定義模塊端口,進而也會考慮使用函數式編程中的map算子對Vec數組進行簡便的連接.這些好處讓他體會到“Chisel高級特性的一以貫之,相輔相成”.

我們對重構之后的Chisel代碼進行評估,結果如表6中第4列(Chisel-opt)所示.令人驚訝的是,和Verilog相比,Chisel-opt的LUT邏輯節省了54.30%,而FF則節省了82.49%!這是因為和工程師編寫的基本元件相比,Chisel標準庫提供的基本元件更成熟,能使用更少的資源實現相同的功能.由于資源的大幅節省,Chisel-opt的性能也得到了進一步的提升.具體地,可運行的最高時鐘頻率提升到154.107 MHz,與Verilog相比提升了13.47%.除此之外,Chisel的高級特性使得Chisel-opt的代碼量更加精簡,和Verilog相比,節省了74.92%的代碼量.

有趣的是,這位工程師一開始看到Chisel-opt的評估數據時,并不相信這一結果,甚至懷疑是本科生的代碼編寫錯誤,導致Vivado對代碼進行了非預期的優化,才使得評估結果大幅優于Verilog.但Chisel-opt確實通過了工程師親自編寫的所有仿真測試,工程師不得不相信Chisel-opt確實可以正確工作.但當他看到Chisel-opt生成可讀性較差的網表級Verilog代碼時,仍然不敢相信,并先后提出“這樣子生成的Verilog代碼,最后的結果應該是挺差勁的才對”、“也許是Chisel生成的代碼太亂了,Vivado正巧才匹配上一些復雜的原語”、“Chisel也許對各種型號的FPGA原語有專門的優化”等各種猜測.工程師對Vivado報告進行詳細的分析,最后發現是自己在RAM中實現的一個性能優化特性消耗了大量的LUT邏輯,把這個特性去掉之后,Verilog消耗的LUT邏輯就減少到與Chisel-opt相當的水平,但這會給當前的Verilog設計帶來額外的延遲,使得仿真測試的性能數據反而不如Chisel-opt.不過關于FF的大量差異,工程師最后仍然找不到可以令他信服的原因.經過這次詳細分析,工程師最后也不得不相信,“使用Chisel開發并不會引入明顯的資源開銷”,“除非FPGA工程師直接調用原語,不然正常情況下只會跟Chisel的資源消耗持平,或者反而消耗更多資源”,甚至表示“如果ASIC也是這樣的趨勢,Chisel肯定是下一代HDL的強力競爭者”.

這個案例很好地展現了一個敏捷開發的例子:一個本科生的Chisel新手,可以在更短的時間內編寫更少的代碼,編碼質量就能達到和工程師相當的水平,甚至還可以超越工程師.即使編碼質量與傳統開發有20%的差距,敏捷開發仍然展現了其節省人力和時間的價值:能快速構建一個可以工作的原型,對項目開展來說是非常有意義的.從這點來看,敏捷開發確實大大降低了硬件開發的門檻.

5 改進與展望

誠然,當前這些項目也有不足之處.例如由于Rocket Chip的迭代速度過快,基于Rocket Chip的研究項目需要花費一定的精力來跟進主線的功能,若跟進后發現主線的改動與研究項目的內容有所沖突,還需要花費額外的精力去解決這些沖突.我們曾經多次參加RISC-V國際研討會,會上不少同行都表示對此感到困擾.同時Rocket Chip項目的版本管理目前也有待完善,截止到本文投稿為止,Rocket Chip在github上的開源倉庫雖然受到廣泛關注,但仍然沒有發布任何穩定的發行版本[31],這對于初次接觸Rocket Chip項目、想尋找一個穩定版本的開發者來說并不友好.

相對來說,對Chisel表達建議的聲音就更多了.首先Chisel的學習曲線比較陡峭,不少硬件開發者比較少接觸面向對象編程,對其編程思維在硬件開發中的應用缺少清晰的認識,而函數式編程對硬件開發者來說就更是遙不可及了.然而關于Chisel語言的資料也較為缺乏,不少開發者因為找不到合適的學習資料而處于觀望狀態,面對充滿Chisel高級特性的Rocket Chip項目更是望而卻步.此外,目前EDA工具對Chisel的支持并不完善,由于Chisel生成的Verilog代碼屬于低層次的網表級別,并不是給硬件工程師閱讀的,讓他們使用EDA工具對這樣的Verilog代碼進行驗證和調試是非常困難的.

事實上,對開源芯片設計來說,開源EDA工具也是一個很重要的部分.我們對目前的開源EDA工具進行了簡單的調研,發現開源EDA工具面臨3個挑戰:1)目前開源的器件庫較少且工藝較老,如Qflow工具支持的最先進器件庫為0.18 μm[32],這限制了芯片的實用性;2)開源EDA工具的可靠性相對較弱,遇到問題時也不易尋求幫助,這是因為這些工具未被廣泛使用,社區較小;3)目前缺少完整高效、靈活可配置且簡單易用的開源EDA工具鏈.

但是,芯片敏捷開發的趨勢是不可阻擋的.據了解,最近一兩年越來越多大型IT企業傳出了擁抱RISC-V的消息[33-34],甚至一些初創企業也嘗試使用Chisel進行項目開發,并表示效果不錯.因此只要給予充分的時間,上述問題是可以解決的.甚至上述部分問題已經被列入了DARPA牽頭的電子復興計劃[35]將要解決的問題列表中.

本文中分享的案例側重于提高前端的編碼效率,但這只是敏捷開發所倡導的其中一項原則.伯克利研究團隊曾經根據自己的經驗提出了硬件敏捷開發宣言[3],包括:1)優先開發未完成但容易改造的原型,而非構建功能齊全卻難以擴展的模型;2)優先組建靈活協作的團隊,而非強調各司其職的分工;3)優先完善工具和生成器,而非改進獨立的設計實例;4)優先擁抱變化,而非遵循計劃.事實上,傳統的觀點認為硬件開發需要使用傳統的開發模型,是因為硬件開發的特點與軟件開發有較大差異.這些差異包括硬件的設計和驗證周期更長、完整的硬件設計流程需要更多更專業的技能(總體架構設計、微結構設計、前端RTL設計和驗證、后端物理設計和驗證)、硬件成品無法進行頻繁的更新等.但伯克利研究團隊認為,正是因為這些差異,我們更需要借鑒軟件開發的經驗來提升硬件開發的效率.例如通過高效的工具和生成器來實現代碼復用,縮短硬件開發周期,節省驗證成本;培養全棧的工程團隊來節省溝通成本;通過管理多個未完成原型的版本來擁抱需求的變化.這些做法背后的原理,和軟件敏捷開發的理念是非常相似的.

伯克利研究團隊的實踐已經展示了敏捷開發的驚人效果:他們在5年時間內進行了11次投片[3],平均每5~6個月完成一款芯片的設計,與傳統的2年設計一款芯片相比,設計效率提高了4~5倍.最近睿思芯科也公布了他們設計的第1款芯片,他們使用RISC-V相關的基礎設施進行芯片的敏捷開發,從零開始到設計完成,只用了7個月的時間[36],是傳統芯片設計效率的3倍.

這些例子說明了,通過敏捷開發來將芯片設計門檻降低幾個數量級,是有可能實現的.我們即將迎來芯片設計的黃金時代,希望更多的有識之士能加入到這股潮流之中.

6 總 結

本文通過分享標簽化RISC-V的項目經驗,分別從設計開源度、定制靈活性、生態完整性以及社區活躍度4個方面,對SPARC V9,MicroBlaze和RISC-V 三種指令集進行比較,說明了開放又活躍的指令集及其開源的微結構設計,是芯片敏捷開發的必要條件.同時本文也介紹了Chisel中有利于敏捷開發的特性,將這些特性與傳統的硬件描述語言進行比較,展示了Chisel代碼的簡潔性、易讀性以及易維護性,從而對項目的敏捷開發提供幫助.最后,本文還將敏捷開發和傳統開發的效率和質量進行對比,結果顯示:敏捷開發能在編碼效率提升一個數量級的同時,達到與傳統硬件開發模式相當甚至更優的性能、功耗與面積.

猜你喜歡
設計
二十四節氣在平面廣告設計中的應用
河北畫報(2020年8期)2020-10-27 02:54:06
何為設計的守護之道?
現代裝飾(2020年7期)2020-07-27 01:27:42
《豐收的喜悅展示設計》
流行色(2020年1期)2020-04-28 11:16:38
基于PWM的伺服控制系統設計
電子制作(2019年19期)2019-11-23 08:41:36
基于89C52的32只三色LED搖搖棒設計
電子制作(2019年15期)2019-08-27 01:11:50
基于ICL8038的波形發生器仿真設計
電子制作(2019年7期)2019-04-25 13:18:16
瞞天過海——仿生設計萌到家
藝術啟蒙(2018年7期)2018-08-23 09:14:18
設計秀
海峽姐妹(2017年7期)2017-07-31 19:08:17
有種設計叫而專
Coco薇(2017年5期)2017-06-05 08:53:16
從平面設計到“設計健康”
商周刊(2017年26期)2017-04-25 08:13:04
主站蜘蛛池模板: 红杏AV在线无码| 国产91小视频在线观看| 欧美在线一级片| 国产原创演绎剧情有字幕的| 日韩天堂网| 国产成人精品视频一区视频二区| 精品三级在线| 在线另类稀缺国产呦| 99久久精品免费观看国产| 夜夜拍夜夜爽| 夜精品a一区二区三区| 天天爽免费视频| 亚洲中文字幕无码爆乳| 青草免费在线观看| 好吊色国产欧美日韩免费观看| 日韩最新中文字幕| 欧美成人区| 久久国产精品国产自线拍| 综合久久久久久久综合网| 国产黄色片在线看| 亚洲性影院| 九九九九热精品视频| 九九久久精品国产av片囯产区| 97se亚洲| 婷婷亚洲最大| 欧美日韩国产综合视频在线观看| 成人免费视频一区| 91在线丝袜| 亚洲人成成无码网WWW| 久久午夜影院| 久久免费观看视频| AV无码无在线观看免费| 国产精品99在线观看| 99久久免费精品特色大片| 中文字幕va| 久久人人妻人人爽人人卡片av| 精品国产自在在线在线观看| 亚洲国产成熟视频在线多多| 九九九精品视频| 欧美日韩成人| 97色婷婷成人综合在线观看| 日本免费一区视频| 国产精品自在拍首页视频8| 一级毛片免费不卡在线| 国产69精品久久久久孕妇大杂乱 | 第一区免费在线观看| 国产精品久久久久久久久| 日本人真淫视频一区二区三区| 无码日韩精品91超碰| 免费三A级毛片视频| 国内精品91| 99热国产这里只有精品9九| 四虎AV麻豆| 日韩国产综合精选| 久久国语对白| 亚洲精品你懂的| 国产99视频在线| 九九香蕉视频| 日韩小视频在线播放| 1级黄色毛片| 欧美日韩va| 91精品人妻互换| 国语少妇高潮| 亚洲成人动漫在线| 91蜜芽尤物福利在线观看| 国产色伊人| 毛片免费试看| 亚洲乱强伦| 成人免费一级片| 人禽伦免费交视频网页播放| 亚洲制服中文字幕一区二区| a级毛片免费网站| 欧美区一区| 亚洲有码在线播放| 午夜国产大片免费观看| 女同国产精品一区二区| 看看一级毛片| 精品国产成人a在线观看| 午夜日b视频| 免费jjzz在在线播放国产| 国产爽妇精品| 久久青草免费91观看|