SV環境構建篇之一:數據類型


從這一部分開始我們將進入SystemVerilog的語言學習和應用。

 

在進入SV(SystemVerilog)之前,如果讀者已經學習過Verilog語言,那么對我們接下來的的從Verilog到SV過渡的部分會容易一些;如果讀者之前也沒有接觸過Verilog語言,也不需要擔心。我們對於SV的三個篇章將會帶你在學習完這三章之后,懂得如何搭建測試平台、以及掌握SV的核心語法、產生測試場景和完成數據比對。

 

之所以在Verilog的基礎上擴展出新的語言SV,為的是構建一種專用的驗證語言,而之前的硬件設計描述語言Verilog和VHDL並不具備如今SV在驗證方面的語言特性優勢,這些優勢包括有:

  • 抽象的數據結構描述可方便於更高層面的驗證需要。

  • 面向對象的軟件編程方式提供了更好地模塊性、封裝性和復用性。

  • 將用於驗證部分的語言屬性用完全軟件化的構建方式實現,使得驗證一側獨立於設計一側。

  • 約束化隨機激勵可提高遞歸測試的收益。

  • 功能覆蓋率收集可量化功能驗證點使得驗證進度更易於反映。

  • 為屬性檢查提供專用分支語言屬性。

 

上述的優點我們也將會在接下來的SystemVerilog圍繞着DUT——MCDF的驗證實例展開:

  • SV的環境構建篇

  • SV的組件實現篇

  • SV的系統集成篇

 

在構思SV的語言介紹過程中,我們認真翻閱了現有的中英文資料和教材,所見到的書籍介紹語言的方式都主要將編程語言作為一門學科進行語法上面的分類。這種方式對於初學者的入門會有幫助,而在具體實踐的環節,好多書籍又無法給讀者一個全面的輪廓和一種循序漸進的直觀感受。所以,本書選擇了在SV的介紹部分一直圍繞着驗證環境建立和實現的具體問題,將核心語言結合着具體場景,讓讀者可以邊學邊掌握該語法、特性可以運用的場景。最后在讀者學完SV部分之后,可以利用所學的語言知識自助構建出驗證平台。

 

我們在介紹語言的過程中,語言的語法特點僅僅是一部分,更重要地在於使得讀者可以懂得該語言特性被應用的場景,實際疑難點在什么地方。因為入門容易精通難,如果讀者手頭已經有一本趁手的SV學習入門資料,且將本書關於SV的部分作為SV的進階應用資料。

 

 


 

相比於Verilog將寄存器(register))類型reg和線網(nets)類型例如wire區分地如此清楚,在SV中新引入了一個數據類型logic。它們的區分和聯系在於:

  • Verilog作為硬件描述語言,傾向於設計人員自身懂得所描述的電路中哪些變量應該被實現為寄存器,而哪些變量應該被實現為線網類型。這不但有利於后端綜合工具,也更便於閱讀和理解。

  • SV作為側重於驗證的語言,並不十分關切logic對應的邏輯應該被綜合為寄存器還是線網,因為logic被使用的場景如果是驗證環境,那么它只會作為單純的變量進行賦值操作,而這些變量也只屬於軟件環境構建。

  • logic被推出的另外一個原因也是為了方便驗證人員驅動和連接硬件模塊、而省去考慮究竟該使用reg還是wire的精力。這既節省了時間,也避免了出錯的可能。

 

與logic相對應的是bit類型,它們均可以構建矢量類型(vector),而它們的區別在於:

  • logic為四值邏輯,即可以表示0、1、X、Z。

  • bit為二值邏輯,只可以表示0和1。

 

那么SV為什么在已經有了四值邏輯的基礎上還要再引入二值邏輯呢?那就是SV在一開始設計的時候,就期望將硬件的世界與軟件的世界分離開。在這里,硬件的世界值得就是硬件設計,所以四值邏輯屬於那里,而軟件的世界即驗證環境,更多的是二值邏輯。所以,有了二值邏輯,驗證環境在進行數據運算的時候不但會提高效率,而且還會省去其它不必要考慮的問題。

 

在這里,我們將四值邏輯的類型和二值邏輯的類型分別摘列出來,請讀者在使用時務必注意:

  • 四值邏輯類型:integer、reg、logic、reg、net-type(例如wire、tri)

  • 二值邏輯類型:byte、shortint、int、longint、bit

 

而通過logic和bit來聲明的矢量均為無符號(unsigned)變量,例如:

 

可以從仿真器中得到的結果是:

 

 

如果按照有符號和無符號的類型進行划分,那么可以將常見的變量類型划分為:

  • 有符號類型:byte、shortint、int、longint、integer

  • 無符號類型:bit、logic、reg、net-type(例如wire、tri)

 

所以,讀者在遇到常見的這些變量類型時,應該注意它們的邏輯類型和符號類型,因為在變量運算中,應該盡量避免兩種不一致的變量進行操作,而導致意外的錯誤。

譬如從下面的例子里,我們可以看到有符號變量和無符號變量混用的運算結果會出乎意料:

 

仿真輸出結果為:

 



我們這里來分析一下:

  1. 一開始 signed_vec 被賦值為 8'b1000_0000,表達為有符號十進制數值為-128。

  2. 在第一次賦值操作時 result_vec = signed_vec,右側的有符號數值-128被賦值到左側,並且需要從8位擴展為9位,且保證有符號數值不變的情況下,首先需要將8'h80擴展為9'h180(均為-128),進而在賦值到左側。

  3. 在第二次賦值操作時,我們首先進行了類型轉換操作 unsigned'(signed_vec),則轉換結果應為十進制數值128,所以在賦值操作以后result_vec = unsigned'(signed_vec),result_vec同signed_vec就比特位的數值沒有發生變化,但是實際表達的十進制數值則從-128被賦值為128。

 

所以,通過上面的例子我們可以發現,在編碼時一定要注意操作符左右兩側的符號類型是否一致,如果不一致,應該首先將其轉換為同一類型再進行運算。

 

對於轉換方式,我們已經上面已經展示了一種轉換方式——靜態轉換,即需要在轉換的表達式前加上單引號即可,而該方式並不會對轉換值做檢查。如果發生轉換失敗,我們也無從得知,所以與之對應的動態轉換$cast(tgt, src)也被經常運用到轉換操作中。靜態轉換和動態轉換均需要操作符號或者系統函數介入,我們統稱為顯式轉換。動態轉換的具體使用方法我們會在隨后關於類和對象的章節着重介紹。

 

而不需要進行轉換的一些操作,我們稱之為隱式轉換,例如下面的例子:

 



仿真結果為:

 



不難發現有兩個問題:

  1. 被轉換的變量為四值邏輯矢量,而被賦值的變量為二值邏輯矢量,且位寬不同。

  2. 在隱式轉換中,x_vec[2:0]被保留下來,x_vec[3]則被丟棄,同時x_vec[0]的值'x'在轉換過程中被轉換為0值,即賦值的最終結果為b_vec = 'b110。

 

從上面的示例中,我們在不同數據類型進行操作時應該注意變量的:

  1. 邏輯數值類型

  2. 符號類型

  3. 矢量位寬

 

 

我們下一節將帶大家進入模塊定義和例化的實際應用。


免責聲明!

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



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