1. 程式人生 > >MyHDL中文手冊(九)—— MyHDL與Verilog協同模擬

MyHDL中文手冊(九)—— MyHDL與Verilog協同模擬

MyHDL與Verilog協同模擬

介紹

MyHDL最令人興奮的一個方面是將其用作硬體驗證語言(HVL)。HVL是一種用於編寫測試臺和驗證環境以及控制模擬的語言。

目前,人們普遍認為HVL應該配備現代化的軟體技術,如面向物件技術。究其原因,驗證是設計過程中最複雜、最耗時的工作。因此,任何有用的技術都是受歡迎的。此外,並不要求測試臺是可實現的。因此,與可綜合程式碼不同的是,對創造性沒有任何限制。

從技術上講,驗證用另一種語言實現的設計需要協同模擬。MyHDL能夠與任何具有過程性語言介面(PLI)的HDL模擬器協同模擬。MyHDL side被設計為獨立於一個特定的模擬器,另一方面,對於每個HDL模擬器,一個特定的PLI模組必須用C語言編寫。目前,MyHDL發行版包含一個用於兩個Verilog模擬器的PLI模組:Icarus和Cver。

hdl inside

為了介紹聯合模擬,我們將繼續使用前面章節中的格雷編碼器示例。假設我們要綜合它,併為此目的用Verilog編寫它。顯然,我們希望重用我們的單元測試驗證環境。

首先,讓我們回顧一下MyHDL中的Gray編碼器的外觀:

from myhdl import block, always_comb

@block
def bin2gray(B, G):
    """ Gray encoder.

    B -- binary input 
    G -- Gray encoded output
    """

    @always_comb
    def logic():
        G.next = (B>>1) ^ B

    return logic

為了顯示協同模擬流程,我們還不需要Verilog實現,只需要介面。Verilog中的Gray編碼器將具有以下介面:

module bin2gray(B, G);

   parameter width = 8;
   input [width-1:0]  B;
   output [width-1:0] G;
   ....

要編寫一個測試平臺,需要建立一個新的模組來例項化被測試的設計(DUT)。測試平臺宣告連線到DUT、刺激生成器和響應檢查器的網和規則(或VHDL中的訊號)。在全HDL流程中,生成器和檢查器是用HDL本身編寫的,但我們希望用MyHDL編寫它們。為了建立連線,我們需要宣告哪些正則和網是由MyHDL模擬器驅動和讀取的。對於我們的示例,此操作如下所示:

module dut_bin2gray;

   reg [`width-1:0] B;
   wire [`width-1:0] G;

   initial begin
      $from_myhdl(B);
      $to_myhdl(G);
   end

   bin2gray dut (.B(B), .G(G));
   defparam dut.width = `width;

endmodule

f r o m m y h d l 調 r e g s M y H D L from_myhdl任務呼叫宣告哪些regs由MyHDL驅動, to_myhdl任務呼叫由它讀取regs&net。這些任務使用任意數量的引數。它們在用C編寫的PLI模組中定義,並以依賴於模擬器的方式提供。在IcarusVerilog中,任務是在從C原始碼編譯的myhdl.vpi模組中定義的。

MyHDL側

MyHDL支援通過協同模擬物件進行協同模擬。協同模擬物件必須知道如何執行HDL模擬。因此,其建構函式的第一個引數是用於執行模擬的命令字串。

生成和執行模擬可執行檔案的方法依賴於模擬器。例如,在Icarus Verilog中,可以通過執行iverilog編譯器獲得示例的模擬可執行檔案,如下所示:

% iverilog -o bin2gray -Dwidth=4 bin2gray.v dut_bin2gray.v

這將通過編譯貢獻的Verilog檔案,生成引數寬度為4的bin2Gray可執行檔案。

模擬本身由VVP命令執行:

% vvp -m ./myhdl.vpi bin2gray

這將執行bin2Gray模擬,並指定使用當前目錄中的myhdl.vpiPLI模組。(這只是一個命令列使用示例;實際上,使用myhdl.vpi模組進行模擬只在協同模擬物件中有意義)。

我們可以使用一個協同模擬物件為MyHDL模擬器提供一個設計的HDL版本。我們編寫的函式不是生成器函式,而是返回協同模擬物件的函式。對於我們的示例和Icarus Verilog模擬器,執行以下操作:

import os

from myhdl import Cosimulation

cmd = "iverilog -o bin2gray.o -Dwidth=%s " + \
      "../../test/verilog/bin2gray.v " + \
      "../../test/verilog/dut_bin2gray.v "

def bin2gray(B, G):
    width = len(B)
    os.system(cmd % width)
    return Cosimulation("vvp -m ../myhdl.vpi bin2gray.o", B=B, G=G)

在可執行命令引數之後,協同模擬建構函式接受任意數量的關鍵字引數。這些引數通過命名關聯將MyHDL訊號與HDL網、規則或訊號聯絡起來。關鍵字是 t o m y h d l to_myhdl或 from_myhdl呼叫中引數的名稱;引數是MyHDL訊號。

完成所有這些之後,我們現在可以使用現有的單元測試來驗證Verilog實現。注意,我們為bin2Gray函式保留了相同的名稱和引數:我們所需要做的就是為現有的單元測試提供這個替代定義。

讓我們在Verilog設計上嘗試一下:

module bin2gray(B, G);

   parameter width = 8;
   input [width-1:0]  B;
   output [width-1:0] G;

   assign G = (B >> 1) ^ B;

endmodule // bin2gray

當我們執行單元測試時,我們得到:

% python test_gray.py
testSingleBitChange (test_gray_properties.TestGrayCodeProperties)
Check that only one bit changes in successive codewords. ... ok
testUniqueCodeWords (test_gray_properties.TestGrayCodeProperties)
Check that all codewords occur exactly once. ... ok
testOriginalGrayCode (test_gray_original.TestOriginalGrayCode)
Check that the code is an original Gray code. ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.706s

OK

限制

在理想的情況下,應該可以用MyHDL無縫地模擬任何HDL描述。此外,每一方的通訊訊號應作為一個單一的透明行為,充分無競爭冒險地操作。

由於各種原因,或許不可能或不希望實現全面的普遍性。任何使用Verilog PLI開發應用程式的人都可以證明,特定模擬器中的限制以及不同模擬器之間的差異可能會非常令人沮喪。此外,與可能足以滿足目標應用程式的稍微不太通用的解決方案相比,完全的通用性可能需要高得不成比例的開發努力。

因此,我試圖實現一個足夠簡單的解決方案,以便人們可以合理地期望任何支援PLI的模擬器都可以支援它,並且這個解決方案比較容易驗證和維護。同時,該解決方案具有足夠的通用性,足以覆蓋目標應用程式空間。

其結果是對HDL程式碼施加某些限制的折衷方案。在本節中,將介紹這些限制。

只有被動的hdl可以協同模擬

MyHDL協同模擬解決方案最重要的限制是只有“被動”HDL才能協同模擬。這意味著HDL程式碼不應該包含任何帶有時間延遲的語句。換句話說,MyHDL模擬器應該是時間的主人;特別是,任何時鐘訊號都應該在MyHDL端生成。

起初,這看起來似乎是一個重要的限制,但如果考慮到協同模擬的目標應用程式,可能就不是了。

MyHDL支援協同模擬,因此HDL設計的測試臺可以用Python編寫。讓我們考慮一下目標HDL設計的本質。對於不打算實現的高階行為模型,我建議直接用MyHDL編寫它們也就不足為奇了;這是MyHDL工作的目標之一。同樣,帶有註釋時序的門級設計不是目標應用程式:靜態時序分析是此類設計的一種更好的驗證方法。

相反,目標HDL設計自然是為了實現的模型,很可能是通過綜合實現的。由於時間延遲在可綜合程式碼中是無意義的,因此該限制與目標應用程式相容。

競爭敏感性問題

在典型的RTL程式碼中,某些事件會導致其他事件在同一時間步長內發生。例如,當時鍾訊號觸發時,某些訊號可能在同一時間步長內發生變化。對於無競爭的操作,HDL必須在一個時間步長內區分這類事件。這是通過“增量”迴圈的概念來完成的。在完全通用的、無競爭的聯合模擬中,聯合模擬器將在增量迴圈級別進行通訊。然而,在MyHDL共同模擬中,情況並不完全如此。

保留了從MyHD器到HDL 協同模擬器的Delta週期。然而,在相反的方向上,他們不是。只有在HDL 協同模擬器中執行了所有增量週期之後,訊號變化才會返回給MyHDL模擬器。

這是什麼意思?讓我們從好訊息開始。正如上一節所解釋的,MyHDL協同模擬背後的概念意味著時鐘是在MyHDL端生成的。當直接使用MyHDL時鐘及其對應的HDL訊號作為時鐘時,協同模擬是無競爭的。換句話說,最能反映MyHDL協同模擬方法的情況是沒有競爭冒險的。

當您希望使用HDL驅動的訊號(以及相應的MyHDL訊號)作為時鐘時,情況就不同了。由這樣的時鐘觸發的通訊不是無競爭的。解決方案是將這種介面視為晶片介面,而不是RTL介面。例如,當資料在正時鐘邊沿觸發時,可以安全地在負時鐘邊沿對其進行取樣。或者,可以用延遲值來宣告MyHDL資料訊號,以便保證它們在時鐘邊緣之後發生變化。

實施說明

本節需要一些PLI術語的知識。

為協同模擬啟用模擬器需要一個用C編寫的PLI模組。在Verilog中,PLI是“標準”的一部分。但是,不同的模擬器實現了標準的不同版本和部分。更糟糕的是,某些PLI回撥的行為沒有在某些基本點上定義。因此,應該計劃為任何模擬器編寫或至少定製一個特定的PLI模組。該版本包含一個用於開源Icarus和Cver模擬器的PLI模組。

本節記錄了PLI模組實現的當前方法和狀態,以及對未來實現的一些思考。

Icarus Verilog

delta增量迴圈實現

為了使協同模擬工作,需要一種特定型別的PLI回撥。回撥應該在處理完所有掛起的事件後執行,同時允許在當前時間步長內建立新事件(例如,通過MyHDL模擬器)。在一些Verilog模擬器中,cbReadWriteSync回撥就是這樣做的。然而,在其他地方,包括Icarus,情況並非如此。回撥的行為沒有完全標準化;一些模擬器在處理非阻塞賦值事件之前執行回撥。

因此,我不得不尋找一個變通辦法。解決方案的一半是使用cbReadOnlySync回撥。此回撥在處理完所有掛起的事件後執行。但是,它不允許在當前時間步長中建立新事件。解決方案的後半部分是將MyHDL delat增量週期對映到真正的Verilog時間點。注意,幸運的是,我在這裡有一些自由,因為這裡的限制是只有被動的HDL程式碼可以共同模擬。

我選擇使Verilog模擬器中的時間粒度比MyHDL模擬器中的時間粒度精細1000倍。對於每個MyHDL時間步,1000個Verilog時間步可用於MyHDL增量週期。在實踐中,每一時間步只需要幾個delta週期。超過此限制幾乎肯定表示設計錯誤;該限制在執行時被檢查。因子1000還使得在列印Verilog時間時很容易區分“實時”時間和增量週期時間。

被動Verilog檢查

如前所述,共同模擬Verilog不應包含延遲語句。理想情況下,應該進行執行時檢查,以標記不相容的程式碼。然而,目前在Icarus模組中沒有這樣的檢查。

可以使用Verilog中的cbNextSimTimeVPI回撥來編寫檢查。然而,Icarus0.7不支援這種回撥。同時,Icarus開發分支增加了支援。當Icarus 0.8釋出時,將新增一個複選框。

同時別這麼做。它可能看起來“工作”,但它實際上不會,因為事件將被錯過的共同模擬介面。

cver

MyHDL協同模擬支援開放原始碼的Verilog模擬器cver。PLI模組是基於Icarus的模組,基本上具有相同的功能。只需要做一些表面修飾。

其他Verilog模擬器

Icarus模組是使用最新一代的Verilog PLI提供的VPI呼叫編寫的。有些模擬器可能只支援TF/ACC呼叫,需要對介面模組進行完全重新設計。

如果模擬器支援VPI,那麼Icarus模組應該在很大程度上是可重用的。然而,有可能在此基礎上加以改進。支援Section Delta Cycle Implementation中描述的增量週期的解決方法可能不是必需的。在某些模擬器中,cbReadWriteSync回調發生在處理完所有事件(包括非阻塞分配)之後。在這種情況下,在Verilog模擬器中不需要更細的時間粒度就可以支援該功能。

還有Verilog標準化工作正在進行中,以解決cbReadWriteSync回撥的模糊性。解決方案是引入新的、定義良好的回撥。通過閱讀一些建議,我得出結論,cbEndOfSimTime回撥將提供所需的功能。

MyHDL專案目前無法訪問商業Verilog模擬器,因此協同模擬支援的進展取決於外部興趣和參與。使用者報告說,他們正在使用MyHDL與來自Aldec和Modelsim的模擬器進行聯合模擬。

中斷的系統呼叫

PLI模組使用讀寫系統呼叫在聯合模擬器之間進行通訊。該實現假設這些呼叫在中斷時由作業系統自動重新啟動。這顯然就是在開發MyHDL的Linux機器上發生的情況。

我們知道應該如何處理未重新啟動的中斷的系統呼叫,但是目前還不能在MyHDL開發平臺上測試這些程式碼。此外,也不清楚這是否仍然是一個與現代作業系統相關的問題。因此,這一問題目前尚未得到處理。但是,已經包含了在發生這種情況時應該觸發的斷言。

每當在PLI模組中觸發斷言時,請報告它。這同樣適用於不容易解釋的Python異常。

那VHDL呢?

如果能有一個與VHDL模擬器(如Modelsim VHDL模擬器)的介面,那就太好了。讓我們總結一下實現這一目標的要求:

我們需要一個到模擬器內部的過程性介面。
過程性介面應該是一種廣泛使用的行業標準,這樣我們就可以在多個模擬器中重用這些工作。
MyHDL是一個開源專案,因此也應該有一個實現過程性介面的開源模擬器。

Verilog的VPI符合這些要求。它是一種廣泛使用的標準,並得到開源Verilog模擬器Icarus和Cver的支援。

然而,對於VHDL來說,情況卻是不同的。雖然存在一種稱為vhpi的標準,但它遠不如VPI流行。而且,據我們所知,只有一個可信的開放原始碼VHDL模擬器(GHDL),而且不清楚它是否具有足夠強大的vhpi功能來滿足MyHDL的目的。

因此,VHDL協同模擬的發展目前被擱置。對於某些應用程式,有一種替代方法:請參見測試工作臺的轉換。