1. 程式人生 > >MyHDL中文手冊(十)——轉換成Verilog和VHDL

MyHDL中文手冊(十)——轉換成Verilog和VHDL

轉換成Verilog和VHDL程式碼

導言

在某些限制之下,MyHDL支援將MyHDL程式碼自動轉換為Verilog或VHDL程式碼。此特性提供了從MyHDL到基於Verilog或VHDL的標準設計環境的路徑。

本章介紹了轉換的概念。具體的例子可以在附帶的章節轉換例子中找到。

解決方案說明

要實現可轉換,硬體描述必須滿足某些限制,即定義為可轉換子集。這在可轉換子集中有詳細描述。

可以使用MyHDL庫中的函式toVerilog或toVHDL將可轉換設計轉換為Verilog或VHDL中的等效模型。

當設計用於實現時,使用第三方綜合工具將Verilog或VHDL模型編譯為ASIC或FPGA的實現。有了這一步,就有了從Python中的硬體描述到FPGA或ASIC實現的自動路徑。

轉換不是從原始檔開始的,而是從Python直譯器詳細闡述的例項化設計開始的。轉換器使用Python探查器來跟蹤直譯器的操作,並推斷設計結構和名稱空間。然後,它有選擇地編譯原始碼片段,以便進行額外的分析和轉換。

特徵

精細化後轉換

精細化elaborate是指對硬體描述的初始處理,以實現可供模擬或綜合的設計例項的表示。具體而言,在此步驟中處理結構引數和構造。在MyHDL中,Python直譯器本身用於精細化。使用詳細的設計例項作為引數構造模擬物件。同樣,轉換工作在一個詳細的設計例項上。因此,儘可能多地使用Python直譯器。

## 任意複雜結構
由於轉換工作在詳細的設計例項上,因此任何建模約束僅適用於設計結構的葉元素,即協同工作生成器。換句話說,對設計結構的描述沒有任何限制:Python的全部功能可以用於此目的。此外,設計層次可以任意深入。

## 生成器對映到Verilog或VHDL結構

轉換器分析每個生成器的程式碼,並將其對映到目標HDL中的等效結構。對於Verilog,它將生成器對映到always塊、連續賦值assign或initial塊。對於VHDL,它將把它們對映到process語句或併發訊號賦值。

從訊號使用情況推斷模組埠

在MyHDL中,埠的輸入或輸出方向沒有顯式宣告。轉換器調查設計層次結構中的訊號使用情況,以推斷訊號是用作輸入、輸出還是用作內部訊號。

介面可轉換

介面:具有多個訊號物件作為其屬性的物件。轉換器通過名稱擴充套件和變形來支援這一點。
函式呼叫對映到Verilog或VHDL子程式。
轉換器分析函式呼叫和函式程式碼。每個函式被對映到目標HDL中的一個適當的子程式:Verilog中的一個函式或任務,VHDL中的一個函式或過程。為了支援Python函式的全部功能,每個Python函式呼叫都會生成一個唯一的子程式。

if-Then-Else結構可以對映到case語句

Python不提供case語句。然而,轉換器識別IF-THEN-ELSE結構,其中變數與列舉型別的項進行順序比較,並使用適當的綜合屬性將這樣的結構對映到Verilog或VHDLcase語句。
列舉型別編碼方案的選擇。
MyHDL中的列舉函式返回列舉型別。此函式接受一個額外的引數編碼,該引數編碼指定實現中所需的編碼:二進位制、一個熱的或一個冷的。轉換器為指定的編碼生成適當的程式碼。

記憶體

某些綜合工具可以將Verilog儲存器或VHDL陣列對映到RAM結構。為了支援這一有趣的特性,轉換器將訊號列表對映到Verilog儲存器或VHDL陣列。

ROM儲存器

一些綜合工具可以從CASE語句中推斷出ROM。轉換器根據更高級別的描述自動擴充套件為case語句。ROM訪問是通過索引成整數的元組,在一行中進行描述的。

有符號演算法

在MyHDL中,處理負數並不重要:只需使用一個intbv物件,並對其值進行適當的約束。相反,Verilog和VHDL在無符號表示和有符號表示之間都起到了不同的作用。要使用負值,使用者必須顯式宣告帶符號的變數。但是,當有符號和無符號運算元混合在一個表示式中時,事情可能會變得棘手。

在Verilog中,當有符號和無符號運算元混合時,所有運算元都被解釋為無符號。顯然,這會導致意想不到的結果。設計人員必須新增符號擴充套件和型別轉換來解決這個問題。

在VHDL中,有符號和無符號的混合通常是不起作用的。設計器必須通過新增大小調整和型別轉換手動匹配運算元。

在MyHDL中,這些問題不存在,因為intbv物件只是作為(受約束的)整數工作。此外,該轉換器實現了Verilog和VHDL語言所需的繁瑣任務的自動化。它根據intbv物件的值約束使用有符號或無符號型別,並自動執行所需的符號擴充套件、大小調整和型別轉換。

使用者定義程式碼

如果需要,使用者可以繞過轉換過程,並描述要插入的使用者定義程式碼。

可轉換子集

導言

不出所料,並不是所有的MyHDL程式碼都可以轉換。雖然限制是重要的,但可轉換子集比RTL綜合子集廣泛得多,而RTL綜合子集是一種工業標準。換句話說,按照RTL綜合規則編寫的MyHDL程式碼,應該始終是可轉換的。但是,也可以為不可綜合的模型或測試臺編寫可轉換程式碼。

當遇到無法轉換的構造時,轉換器嘗試發出明確的錯誤訊息。

回想一下,任何限制只適用於精細化後的設計。在實踐中,這意味著它們只應用於生成器的程式碼,即MyHDL設計中的葉功能塊。

編碼方式

對可轉換程式碼的一個自然限制是,它應該以MyHDL風格編寫:協作生成器、通過訊號進行通訊以及以敏感的方式指定恢復條件。

對於純建模,如何建立生成器並不重要。但是,在可轉換程式碼中,應該使用MyHDL Decorator中的一個來建立它們:例項instance、總是always_seq或always_comb。

支援的型別

最重要的限制是物件型別。只能轉換有限數量的型別。Python int和long物件對映到Verilog或VHDL整數。所有其他支援的型別都需要具有定義的位寬度。支援的型別是Python bool型別、MyHDL intbv型別和函式列舉返回的MyHDL列舉型別。

必須構造intbv物件,以便可以推斷位寬度。這可以通過指定最小值和最大值來完成,例如如下所示:

index = intbv(0, min=MIN, max=MAX)

Verilog轉換器支援可以採用負值的intbv物件。

或者,也可以從intbv物件獲取切片,如下所示:

index = intbv(0)[N:]

例如Slice返回一個新的intbv物件,其最小值為0,最大值為2*N。

除了上面描述的標量型別之外,轉換器還支援許多基於元組和List的型別。下表總結了MyHDL型別的對映。

MyHDL type VHDL type Notes Verilog type Notes
int integer integer
bool std_logic (1) reg
intbv with min >= 0 unsigned (2) reg
intbv with min < 0 signed (2) reg signed
enum dedicated enumeration type reg
tuple of int mapped to case statement (3) mapped to case statement (3)
list of bool array of std_logic reg (5)
list of intbv with min >= 0 array of unsigned (4) reg (4)(5)
list of intbv with min < 0 array of signed (4) reg signed (4)(5)

注:(1) VHDLSTD_LOGIC型別在標準VHDL軟體包IEEE.std_Logic_1164中定義。
(2) 使用的VHDLunsignedandsignedtype是來自標準VHDL包IEEE.NUMERIC_STD的型別。
(3) int的MyHDL元組用於ROM推理,只能以一種非常特殊的方式使用:對元組的索引操
作應該是賦值的RHS。
(4) 所有列表成員應具有相同的值約束。
(5) 列表對映到Verilog儲存型別。

該表適用於MyHDL變數。 轉換器還支援使用bool、intbv或enum物件作為底層型別的MyHDL訊號。對於VHDL,它們被對映到具有上表中指定的底層型別的VHDL訊號。Verilog沒有訊號的概念。對於Verilog,MyHDL訊號被對映到Verilog暫存器reg,如上表所示,或者對映到Verilog導線wire,具體取決於訊號的使用情況。

如果底層訊號型別為bool或intbv,轉換器支援MyHDL訊號列表。它們可以對映到具有在表中指定的VHDL型別的VHDL訊號,或者對映到Verilog儲存器。然而,訊號列表並不總是對映到相應的VHDL或Verilog物件。有關更多資訊,請參見訊號列表的轉換。

支援的語句

以下是Verilog轉換器支援的語句列表,可能帶有限制或使用說明。

assert

Python中的Assert語句如下所示:

assert test_expression

如果test_expression是可轉換的,則可以對其進行轉換。

break
continue
def
for
唯一支援的迭代方案是通過內建函式範圍或MyHDL函式下降範圍返回的整數序列進行迭代。不支援可選的Else子句。

if
完全支援if、elif和Else子句。pass
Print
具有多個引數的列印語句:

print arg1, arg2, ...

是支援的。但是,這些引數是有限制的。首先,它們應該是下列形式之一:

arg
formatstring % arg
formatstring % (arg1, arg2, ...)

其中arg是一個bool、int、intbv、enum或這些型別的訊號。

與Python一樣,格式化字串包含普通字元和轉換說明符。但是,唯一支援的轉換說明符是%s和%d。因此,不支援對正和寬度規範。

不支援不帶換行符的列印:

print arg1 ,

raise
此語句對映到以錯誤訊息結束模擬的語句。
return
yield
用於指定靈敏度列表。所產生的表示式可以是訊號、由MyHDL函式Signal.posedge或Signal.negedge指定的訊號邊緣,也可以是訊號和邊緣規範的元組。它也可以是延遲物件。

while
不支援可選的Else子句

支援的內建函式

下面是轉換器支援的內建函式的列表。

bool
布林函式可用於將物件顯式地型別化為其布林解釋。
len
對於Signal和intbv物件,函式len返回位寬度。
int
此函式可用於將物件顯式地型別化為其整數解釋。

檔案串

轉換器以Python文件字串的形式傳播註釋。
在Python中,Docstring通常用來以標準的方式記錄某些物件。這樣的“正式”文件字串被放入轉換後的輸出中的適當位置。轉換器支援頂級模組和生成器的正式文件字串。
在生成器中,“非官方”文件字串也會被傳播。這些字串(按慣例用三重引號)可以出現在語句之間的任何位置。
Python解析器忽略常規的Python註釋,並且它們不存在於解析樹中。因此,它們不會被傳播。使用docstring,您可以一種優雅的方式指定哪些註釋應該傳播,哪些不應該傳播。

訊號列表的轉換

訊號列表在許多方面都很有用。例如,它們使建立重複結構變得容易。另一個應用程式是記憶體行為的描述。
轉換器的輸出是非層次化的。這意味著所有訊號都是在VHDL或Verilog(作為VHDL訊號,或Verilog規則和連線)的頂層宣告的。但是,作為MyHDL設計層次結構中某個級別的列表成員的一些訊號可以用作較低級別的普通訊號。對於這樣的訊號,必須選擇是宣告Verilog記憶體還是VHDL陣列,還是宣告多個普通訊號名稱。
如果可能,最好是純訊號宣告,因為Verilog儲存器和陣列在使用和工具支援方面有一些限制。如果在生成器程式碼之外嚴格使用列表語法,這是可能的,例如,當使用訊號列表來描述結構時。
相反,在某些生成器中使用列表語法時,將宣告Verilog記憶體或VHDL陣列。典型的例子是RAM儲存器的描述。

介面轉換

複雜的設計通常有許多訊號傳遞到不同的層次結構中。通常,許多訊號在邏輯上屬於同一類訊號。這可以由一個介面來建模:一個具有多個訊號物件作為其屬性的物件。將訊號分組到介面中可簡化程式碼、提高效率並減少錯誤。
該轉換器支援使用分層名稱擴充套件和名稱更改的介面。

賦值問題

Python中的名稱指定。
Python中的名稱賦值與許多其他語言中的名稱賦值是一個不同的概念。這一點對於Python中的有效建模非常重要,對於可綜合的MyHDL程式碼更是如此。因此,這裡對這些問題進行了明確的討論。
請考慮以下名稱賦值:

a = 4
a = ``a string''
a = False

在許多語言中,其含義是現有變數a獲得許多不同的值。在Python中,這樣的變數概念並不存在。相反,賦值只是建立一個名稱到某個物件的新繫結,該繫結將替換以前的任何繫結。因此,在本例中,名稱a按順序綁定了許多不同的物件。

轉換器必須研究MyHDL程式碼中的名稱賦值和使用,並將名稱對映到Verilog或VHDL物件。為此,它嘗試推斷分配給名稱的每個表示式的型別以及可能的位寬。

如果可以確定分配中使用了一致的型別和位寬度,則可以支援同一名稱的多個分配。這可以用於布林表示式、數字表達式和列舉型別的文字。

在其他情況下,建立物件時應使用單個賦值。然後通過修改現有物件來實現後續的值更改。此技術應用於訊號和intbv物件。

訊號賦值

MyHDL中的訊號賦值是使用屬性賦值來實現的。因此,值更改是通過修改現有物件來建模的。轉換器研究訊號物件以推斷相應Verilog或VHDL物件的型別和位寬。

intbv物件

intbv型別很可能是MyHDL中可綜合建模的主要工具。intbv例項的行為類似於一個(可變的)整數,其各個位都可以訪問和修改。此外,還可以約束其值集。除了錯誤檢查,這使得推斷位寬度成為可能,這是實現所必需的。

如前所述,不可能使用名稱賦值來修改intbv物件的值。在接下來的部分中,我們將展示如何實現這一點。考慮:

a = intbv(0)[8:]

這是一個初始值為0且位寬為8的intbv物件。要將其值更改為5,可以使用切片指定:

a[8:] = 5

也可以通過保留未指定的位寬來實現這一點,這意味著更改“所有”位:

a[:] = 5

通常,新的值將取決於舊的值。例如,要使用上述技術遞增intbv,請執行以下操作:

a[:] = a + 1

Python還提供了增強的賦值操作符,該操作符可用於實現就地操作。這些是由intbv物件和轉換器支援的,因此增量也可以執行以下操作:

a += 1

從轉換中排除程式碼

對於某些任務(如除錯),插入不應轉換的任意Python程式碼可能很有用。

轉換器通過忽略 if debug 測試中嵌入的所有程式碼來支援此功能。不考慮 debug 變數的值。

使用者定義程式碼

MyHDL提供了一種在轉換過程中包含使用者定義程式碼的方法。有一些特殊的函式屬性被轉換器理解,但被模擬器忽略。這些屬性分別是Verilog的verilog_code和VHDL的vhdl_code。它們的操作就像一個特殊的返回值。當在MyHDL函式中定義時,轉換器將使用它們的值而不是常規的返回值。實際上,在這一點上,它將停止轉換。

verilog_code或vhdl_code的值應該是Python模板字串。模板字串支援基於$的替換。
$name表示法可用於引用字串上下文中的變數名。轉換器將替換字串中的適當值,然後插入它而不是常規轉換的輸出。

使用者定義的程式碼還有一個問題。通常,轉換器會推斷輸入、內部訊號和輸出。它還檢測非驅動和多驅動訊號。要做到這一點,它假設訊號不是預設驅動的。然後,它處理程式碼以找出哪些訊號是從哪裡驅動的。

正確的訊號使用推斷不能使用者定義的程式碼來完成。在沒有使用者幫助的情況下,這將導致在推理過程中出現警告或錯誤,或者導致無效程式碼的編譯錯誤。使用者可以通過設定從使用者定義的程式碼中驅動或讀取的訊號的DrivenRead屬性來解決此問題。預設情況下,這些屬性為false。受驅動屬性的允許“true”值為True、‘wire’和‘reg’。後兩個值指定使用者定義的Verilog程式碼如何在Verilog中驅動訊號。要決定使用哪個值,請考慮插入使用者定義的程式碼後如何在Verilog中宣告訊號。

有關使用者定義程式碼的示例,請參見使用者定義程式碼。

模板變換

注:此部分僅與VHDL相關。

VHDL和Verilog在確定訊號邊緣靈敏度的方法上存在差異。在Verilog中,邊緣說明符可以直接在靈敏度列表中使用。在VHDL中,這是不可能的:只能在靈敏度列表中使用訊號。要檢查邊緣,可以在程式碼中使用rising_Edge()或falling_Edge()函式。

MyHDL遵循Verilog方案在靈敏度列表中指定邊緣。因此,在將這些程式碼對映到VHDL時,需要將其轉換為等價的VHDL。這是一個重要的問題,因為它影響所有推斷順序邏輯的可綜合模板。

我們將用一些例子來說明這一特性。以下是D觸發器的MyHDL程式碼:

@always(clk.posedge)
def logic():
    q.next = d

將其轉換為VHDL,如下所示:

DFF_LOGIC: process (clk) is
begin
    if rising_edge(clk) then
        q <= d;
    end if;
end process DFF_LOGIC;

轉換器可以處理更一般的情況。例如,以下是具有非同步設定、非同步重置和設定優先於重置的D觸發器的MyHDL程式碼:

    @always(clk.posedge, set.negedge, rst.negedge)
def logic():
    if set == 0:
        q.next = 1
    elif rst == 0:
        q.next = 0
    else:
        q.next = d

將其轉換為VHDL,如下所示:

DFFSR_LOGIC: process (clk, set, rst) is
begin
    if (set = '0') then
        q <= '1';
    elsif (rst = '0') then
        q <= '0';
    elsif rising_edge(clk) then
        q <= d;
    end if;
end process DFFSR_LOGIC;

所有具有實際效用的案件都可以用這種方式處理。但是,也有一些情況不能轉化為等價的VHDL語言。轉換器將檢測這些情況並給出錯誤。

轉換輸出的聯合模擬驗證

注: 本節僅與Verilog相關。

為了驗證轉換後的Verilog輸出,可以使用協同模擬。為了簡化這項工作,轉換器還生成了一個測試平臺,該測試平臺使得使用Verilog協同模擬介面模擬Verilog設計成為可能。這允許使用與MyHDL程式碼相同的測試平臺來驗證Verilog程式碼。

試驗平臺的改裝

轉換後,顯然需要驗證VHDL或Verilog程式碼是否正確工作。對於Verilog,我們可以使用前面討論的聯合模擬。但是,VHDL目前不支援協同模擬。

另一種方法是對測試平臺本身進行轉換,這樣測試平臺和設計都可以在HDL模擬器中執行。當然,這不是一個完全通用的解決方案,因為可以轉換的程式碼型別有重要的限制。因此,問題是轉換限制是否允許開發足夠複雜的測試臺。在本節中,我們將對此提出一些見解。

最重要的限制是可以使用的型別,如本章前面所討論的。但是,“可換子集”比“綜合子集”更寬。我們將介紹一些測試工作臺感興趣的非綜合特性。

while迴圈
而迴圈可用於高階控制結構。
raise宣告
Rise語句可以在錯誤情況下停止模擬。
delay物件
延遲建模對於測試臺架是必不可少的。
print語句
可以使用Print語句進行簡單除錯。
assert語句
最初,Assert語句只打算在程式碼中插入除錯斷言。最近,有一種趨勢是使用它們來編寫自檢單元測試,由單元測試框架(如py.test)控制。特別是,它們是為MyHDL設計編寫自檢測試臺的強大方法。由於Assert語句是可轉換的,MyHDL中的整個單元測試套件可以轉換為Verilog和VHDL中的等效測試套件。

此外,可以使用與可綜合程式碼相同的技術來控制複雜性。具體地說,生成器外部的任何程式碼都是在精細化elaborate過程中執行的,因此在轉換過程中不會被考慮。例如,此功能可用於設定常數或預期結果的複雜計算。此外,可以使用int的元組來儲存將對映到Verilog和VHDL中的case語句的值表。

方法學說明

第一步模擬

在Python哲學中,執行時規則。除了語法錯誤之外,Python編譯器不會嘗試檢測很多錯誤,考慮到Python的超動態特性,這無論如何都是一項幾乎不可能完成的任務。要驗證Python程式,應該執行它,最好使用單元測試來驗證每個特性。

在將MyHDL描述轉換為Verilog時,應該使用相同的原理:首先確保模擬執行良好。儘管轉換器檢查了許多事情並試圖發出明確的錯誤訊息,但是除非模擬執行正常,否則不能保證它執行了有意義的工作。

處理層次

回想一下,轉換髮生在精細化elaborate之後。結果是轉換後的輸出是非分層的。在許多情況下,這不是一個問題。轉換的目的是通過使用Verilog和VHDL作為“後端”格式提供到傳統設計流程的路徑。層次結構與人類是相當相關的,但對工具卻不是那麼重要。

但是,在某些情況下,層次結構是可取的。例如,如果轉換測試工作臺,則可能希望將其程式碼與測試中的設計分開。換句話說,轉換應該在測試例項下的設計停止,並插入一個例項化。

有一種解決方法可以通過少量的額外工作來實現這一點。解決方法是定義由被測試設計的例項化組成的使用者定義程式碼。正如在使用者定義程式碼中所討論的,當轉換器看到鉤子時,它將停止轉換並插入例項化。當然,您也需要轉換測試中的設計本身。因此,您應該使用一個控制是否定義掛鉤的標誌,並根據所需的轉換對其進行設定。