【原創】SystemVerilog中的淺復制(shallow copy)和深復制(deep copy)


使用SystemVerilog搭建環境的時候,經常會遇到需要對一個對象進行復制,以防止對象的方法修改原始對象的值。對於初學者經常會使用new函數來實現class的內建的復制功能,但是,當要復制的對象中含有其他對象(object)時,使用內建的復制功能將會得到不期望的結果。本文將示例說明shallow copy和deep copy的區別。

1 淺復制(shallow copy)

在SystemVerilog中,當一個class聲明時會指定一個句柄handle(可以理解為其他語言中的指針),該句柄handle指向一塊存儲空間,該存儲空間后續只能存放該class數據類型的數據。在沒有對其進行任何操作之前,該handle相當於沒有指向任何實際的數據對象,只有在使用了new函數之后,才會為其開辟具體的存儲對應class類型數據的存儲空間。

【示例】

 

示例中構造函數new()被調用后,就會創建一個transaction的實例,這時就會為其開辟一塊存儲transaction數據類型的空間,聲明的句柄tr就指向該空間的起始地址。

那么如果又聲明了一個transaction的句柄tr1,將舊句柄賦值給該變量或者使用new將舊句柄拷貝給新的句柄,即tr1 =tr(或tr1 = new tr;),此時會將tr中的所有變量復制給tr1,但是tr中的new函數都不會被調用。

【示例】

 

【仿真結果】

 

示例中,tr1中的所有屬性變量被復制到了tr2中,這種操作方式相當於對tr1進行了簡單盲目的復制操作,其執行過程如下圖所示:

 

但是其使用還是存在一定的問題,如果屬性成員中存在具有類屬性的成員時,復制后操作的結果可能跟期望不一致,下例所示。

【示例】

 

【仿真結果】

 

示例中,tr1被復制給tr2,此時第一次打印和第二次打印輸出的結果是一樣的。再通過tr2修改了被復制的pkt中的屬性payload為’hBA,但是在第三次和第四次分別打印輸出的結果卻不一樣,除了tr1的變量屬性成員不一樣外,pkt.payload一樣,都是修改后的’hBA。這是因為雖然tr1被復制給了tr2,此時tr1中的句柄pkt也被復制給了tr2,而句柄本身可以理解為指針,那么相當於tr2和tr1使用了相同的指針句柄,此時如果對tr1或者tr2中的句柄指向的內容進行了修改,相當於對於tr1和tr2中pkt句柄共同指向的空間進行了修改,所以此時雖然僅僅修改了tr2,但是tr1中pkt指向的空間的內容也被其同時修改了。而且可以通過實際仿真結果可以看出,tr中new函數中的“pkt = new()”在復制時並沒有被執行,因為如果該new函數被執行的話,那么tr1被復制后,tr2中的pkt和tr1中的pkt是會不一樣的,即tr1和tr2中的pkt會指向不同的空間。其執行過程如下圖示意所示:

 

因此可以得到下面的結果:

淺復制會將所有的變量包括integers,strings,intance handle(指針)等等被復制過去。
對一個對象進行復制,復制過程不會調用構造函數,所以也不會使用構造函數對變量的初始化。
可見,淺復制是將原始對象中的所有屬性拷貝到新對象中去,將句柄屬性復制到新對象中去,不把“句柄指向的對象”復制進去,所以原始對象和新對象引用同一對象,新對象中的句柄指向的內容發生變化會導致原始對象中的對應內容也發生變化。因此,為了實現復制后的兩個對象互相不影響,就不能使用class默認內建復制操作(淺復制),此時就需要采用深復制。

2 深復制(deep copy)

為了避免產生淺復制后的藕斷絲連,我們需要對原有的class進行適當的修改完善,實現對象的深復制。深復制相較淺復制是在引用方面不同,深復制就是創建一個新的和原始句柄指向的內容相同的字段,是兩個一樣大的數據段,所以兩者的句柄指向的空間是不同的,但內容是相通的,之后的新對象中句柄指向的內容發生改變,不會引起原始對象中句柄指向內容也發生改變。

【示例】

 

【仿真結果】

 

示例中,tr1通過transaction的copy函數被復制給tr2,此時第一次打印和第二次打印輸出的結果是一樣的。再通過tr2修改了被復制的pkt中的屬性payload為’hBA,在第三次和第四次分別打印輸出的結果不一樣,除了tr1的變量屬性成員不一樣外,pkt.payload也不一樣,tr2此中的pkt指向的payload值為’hBA,而tr1中的pkt只想的payload的值為’hAB,即此時tr1和tr2中的pkt指向的payload值已經是不一樣的了。這是因為雖然tr1使用transaction的copy函數被復制給了tr2時調用了packet的copy函數,即此時將tr1中的pkt指向的對象復制了一份給tr2,此時tr1和tr2中的pkt指向的對象不再是同一個對象了。因此tr1和tr2對pkt進行修改復制就不會相互影響了。其執行過程如下圖示意所示:

 

因此,在SystemVerilog中,如果要為所使用的類使用deep copy時,就需要為所有的相關class定義好copy函數,為了避免一些因為coding導致的錯誤,在UVM中已經集成了copy和clone操作,用戶在使用時已經完全不需要在單獨額外的編寫copy函數,盡管調用即可。

下圖個人技術微信公眾號,歡迎朋友們關注溝通!

 

 本文純屬學習之用,歡迎指正文中不足,

封面圖片若有侵權,請及時溝通!


免責聲明!

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



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