1. 程式人生 > >我跟你談SV介面類,你卻以為我跟你談介面?

我跟你談SV介面類,你卻以為我跟你談介面?

本文轉自:

http://www.eetop.cn/blog/html/28/1561828-6339382.html

http://www.eetop.cn/blog/html/28/1561828-6339383.html

這個話題已經積鬱在胸口很久了,然而各種事情每天都在侵佔著路桑的大(ling)腦(hun),關於介面類(interface class)的介紹和應用一拖再拖,直到今天無意間翻出一篇很好的文章,來自於ARM公司Stan Sokorac。

SystemVerilog Interface Classes - More Useful Than You Thought (2nd place best paper award)

 

在發表這篇論文的時候,他已經是ARM的senior principle...看了他的LinkedIn,雖然在論文上面不多產,但是他的另外一篇,也是我特別想介紹的,就是2017年US DVCon的最佳論文。

Optimizing Random Test Constraints Using Machine Learning Algorithms (1st place, best paper award)

 

從他的計算機工程背景和技能樹來看,做驗證如果想要突破,必須得從軟體開發入手,重新學習設計模式,繼而在UVM的結構平臺上面做定製化開發,不然也只能吃UVM標準的套餐了。

Stan Sokorac先生已經從ARM離職,到一家Tenstorrent開發深度學習處理器去了...不得不說,SoC模式限制了我的想象力啊。

 

接下來那我主要就Sokorac先生的這篇論文來談介面類在驗證平臺中的實踐

 

概述

interface在SV中已經被“介面”即通訊連線所指的語義所佔領了。而在軟體世界中,例如Java、C#、Swift、D等語言都支援另外所指的interface軟體程式設計方式。所以諸君請對這篇文章中的interface(介面)加以辨別,即我們會談到SV標準中的interface class的用法。不過由於介面類的概念是在SV 2012標準中提出,而在OVM、UVM的標準制定已經更早,因此SV與UVM在這一有用的介面類推廣上面失之交臂。

 

實際上,這一影響要更加深遠,由於缺少UVM標準的助力,而大多數verifier又直接面向UVM而非SV的驗證平臺,所以介面類這一新的特性並沒有被很好地推廣開來,甚至被低估或者不被喜愛。而對於習慣軟體思維模式的資深verifier,例如Sokorac先生,介面類簡直是任其在UVM介面中衝浪的帆板,別提多自由了。我們有幸得到這份非常高質量而又語言簡明易懂的論文,可從中窺得ARM公司在處理器驗證時的一些定製化使用方式。

 

實際上路桑所在的公司也有基於UVM深度定製的一些驗證平臺和軟體包,其中一些已經在或者將在DVCon、SNUG這些會議中發表,一些仍然還身處深閨人未識。有興趣的童鞋,可以在路桑的個人網頁下載路桑以及其它的優秀論文。路桑的個人網址如下:

www.rockeric.com

 

 

接下來路桑將參考論文,給出四種介面類的典型使用方式。儘量取其精華(實際上全部都是精華,很難再分割摘取),使諸君認識或者重新認識介面類的藍籌地位,也希望好學的童鞋可以下載此文,多加閱讀幾遍,在接下來的大型UVM結構模式中,如果你發現uvm_event或者uvm_analysis_port的使用讓你程式碼增多、維護變得繁重的時候,希望你可以想起來還有介面類這樣一種清爽的框架實現方式。

 

A. 觀察者(subscriber)模式

在以往monitor檢測到資料需要傳送至各個checker或者scoreboard,甚至多個的情況下,需要進行如下操作:

  • 在更高層環境的connect階段就確定連線關係,即monitor(publisher)與其它收聽元件(listener)的關係,例如checker或者scoreboard。

  • 在連線時,需要使用uvm_analysis_port完成“一對多”的資料傳送要求,並且在各個收聽元件側,需要實現相應的write()方法

 

不過這樣做也有一些限制,例如對於由SV而非UVM搭建的測試平臺無法很好地實現一對多的資料傳送,同時由於連線關係是“靜態”的,使得無法在run的階段隨時新增資料傳送管道,並且也只有uvm_component才可以參與到TLM埠連線關係當中,因此如果是sequence與test或者driver之間發生事件控制的訂閱關係,那麼sequence只能通過其p_sequencer延伸到元件層次關係,再利用p_sequencer與其它元件完成通訊,非常地掣肘。

 

另外一個不方便的地方在於,每次通訊只能先於一種單一的事務,如果想要傳遞兩個以上不同種類的事務,則需要將一個事務作為成員,封裝在另一個事務中,也不方便,所以這是由於write()方法的單一引數所帶來的不便。

 

那如果我們使用了介面類,世界會不會變得有序而靈活呢?來看下面這個例子,首先宣告一個介面類resolve_listener,接下來,所有需要從monitor接收資料的元件在定義時,需要使用宣告“implements resolve_listener”,即表示它們的定義中會實現new_resolve()方法,即處理從monitor接收到資料的方法。那麼monitor呢?它只需要將所有的listener宣告為佇列m_resolve_listener[$],因為它也不知道會有多少個監聽它的元件,而在run階段,當它每次廣播的時候,它就會利用foreach每次輪詢呼叫各個監聽元件的new_resolve()方法。

 

 

那麼monitor與所有監聽元件例如resolve_checker的聯絡發生在哪兒呢?

  • 凡是監聽元件建立時,需要呼叫m_config.monitor.add_listener(this),新增其到monitor的廣播列表裡

  • 凡是monitor在廣播時,將會對收聽列表中的所有元件一一廣播其事務arm_txn_resolve。

 

再來看,通過介面類實現了什麼幫助呢?

  1. 不再依賴於UVM的uvm_analysis_port,即在任何SV環境中都可以完成一對多的廣播-收聽(publish-listen)軟體設計模式。

  2. 不再要求所有的連線需要發生在UVM的connect階段,也不需要廣播方或者收聽方必須是uvm_component,這大大提高了實現便利性,脫離了UVM的組織結構限制。例如sequence與test或者driver可直接實現通訊,不再需要間接通過sequencer來周折完成。

  3. 對於廣播的方法,不再限定於其內容和引數個數,因此當需要傳遞多個引數時,利用介面類將比TLM傳送事務更加方便。

 

B. 偽多繼承(pseudo-multiple-inheritance)

SV無法直接實現多繼承,使得不少從specman或者軟體世界遷移過來的人產生遺憾。多繼承是AOP的典型特性,可以檢視我們之前的一篇文章:

OOP(面向物件)的硬體設計思路就夠頭疼了,還搞什麼AOP?

 

這篇文章中提到了在處理器的指令驗證中,難免有一些“複合”指令,即C指令的特性可能是由A指令和B指令的合集。例如Load、Store與DMB的型別指令是在繼承樹上是分開的,但是Load-Acquire(LDAR)或者Store-Release(STLR)則是由之前兩種指令型別的組合

 

在實現LDAR的指令定義時,按照SV的侷限,我們可能依然繼承於Load指令,而採用程式碼“拷貝”的方式,將另外一部分指令程式碼從DMB類從完全拷貝過來,但這難免會給程式碼維護帶來麻煩。或者也可以將它們之間的公共程式碼放在公共檔案內,繼而凡是使用到這些方法的類,例如DMB或者LDAR都採用`include的方式來完成程式碼編輯工作,不過這還是會讓程式碼不那麼直接,曲徑通幽。

 

而我們可以利用介面類,將這一共同部分抽象出來,再分別由LADR和DMB指令類“implement barrier”,並實現預定義的方法。對於LADR,它的定義形式則變為了“class ladr extends load implements barrier”,實現了從分別繼承於load和barrier的目的。

 

C. 資料序列組織

對於複雜環境的除錯,小夥伴們是怎麼做的?路桑指的是,如果有多個UVC在傳送、監測不同種類的事務,那麼你是如何記錄和分析他們的?一些模擬器有較靈活的監測方式,例如Questasim的事務記錄功能就不錯,還有VCS的SmartLog也能提供一些幫助。不過還是比不上自己定製化的來得貼心好用,而Sokorac分享的一種在原有驗證環境基礎上可以直接擴充套件的,只需新增少量程式碼的解決方案,可以將模擬時間視窗中,任何型別的事務都統一到一個除錯方案中,例如統一的TLM事件定義:

 

而對於專案中新定義的事務,只需要在以往繼承於uvm_sequence_item的事務,附帶“implements arm_event”,實現其預定義的方法即可完成統一的事件格式,繼而在事務建立時(new()函式),可利用中心化的arm_event_recorder完成統一的、序列的模擬資料組織,繼而將資料格式高度統一化、序列化,便於後期的資料跟蹤除錯,也使得資料的來源、目的地、資料之間的聯絡一目瞭然。

 

 

那麼如果是已有的環境,已經定義過的sequence item的舊環境,還有救嗎?當然!可以在原有程式碼(如果允許修改的話),新增如上的程式碼即可;如果是商業VIP庫,那麼我們可以考慮採取定義子類,再由頂層覆蓋(override)的方式,使得原有環境中所有的sequence item可以最終取得一致的資料型別,並且在建立時可以自動完成資料記錄工作。

 

D. 物件化計時方式

最後這個話題更加有趣,在驗證環境中,我們經常會採用@clk的方式來增加延遲,然而這種方式使得程式碼修改時,非常容易影響隨機數生成器(RNG, Random Number Generator)的穩定性。關於隨機發生器穩定性的討論,可以閱讀路桑這篇文章:

SV元件實現篇之六:激勵器的隨機化(下)

 

為了提高隨機的穩定性,可以將所有的時鐘等待方法都交由中心化的計時器物件處理。這裡中心化的計時物件型別為clocking_center,它也採取輪詢的方式為每一個需要時鐘的物件進行“授時”。而對於以前需要獨立等待時鐘的各個元件,例如interface_timeout_monitor類,則可以一開始進行授時需求登記(connect階段),而在介面類clockable的計時方法中tock()實現中,進行計時的邏輯實現。由此完成了中心化的授時工作,而分散的元件則只需要實現每次計時的邏輯,不再需要出現“@clk”的語句。簡單來看,更新後的元件則不再需要任何時鐘等待,這也促進了隨機過程的穩定性。

 

總結

這篇論文介紹的四種方式都非常有幫助,可謂讓人大開眼界。

 

廣播-收聽的設計模式可以利用介面類進一步提高靈活性,不過值得探討的是,UVM的哲學是重視結構穩定性的,即TLM埠都是為了完成元件之間的通訊,而在設計時並沒有為sequence與uvm_component通訊預留方法。如果廣泛地引入介面類實現任何物件之間的通訊,那需要考慮程式碼的一致性,而不是各種混雜使用容易給程式碼維護造成負擔。另外,路桑還是認為UVM新手不應該太自由太任性,需要UVM套路的管束。待其理解UVM哲學後,使用SV的介面類,則可以協助其完成平時只有依靠uvm_event或者其它方式才能完成的物件通訊。

 

多繼承的模式也能減輕程式碼的體積,簡化類的繼承層次。由此,verifier可在類定義時進一步抽象,哪些行為可能是介於多種不同類的共同行為,而考慮將其抽象為介面類。資料的序列結構化可以在已有環境上完成資料格式的統一化,便於後期的資料統計分析和除錯跟蹤

 

這篇文章值得多看多回顧,在將來如果遇到上述的一些困難,希望你腦海裡還能閃過一個概念——“介面類(interface class)”而不是“介面(interface)”。