聊一聊SpinalHDL 1.9.4版本中的PackedBundle、PackedWordBundle的使用
位域的提取與封裝 在邏輯設計里,但凡牽涉到協議,一般都避免不了協議字段的提取。以下面的一個簡單協議為例:
這里256bit輸入數據,包含了五個協議字段:
host_addr:64 bits
card_addr:64 bits
length:14 bits
sop:1 bits
eop:1 bits
在進行協議解析時,我們可能會定義如下數據類型:
caseclassDescriptor() extendsBundle{ val host_addr=UInt(64bits) val card_addr=UInt(64bits) val length=UInt(14bits) val sop=Bool() val eop=Bool() override defassignFromBits(data:Bits)={ host_addr.assignFromBits(data(0,64bits)) card_addr.assignFromBits(data(64,64bits)) length.assignFromBits(data(128,14bits)) sop:=data(144) eop:=data(145) } override defasBits():Bits={ eop##sop##B(0,2 bits)##length##card_addr##host_addr } }
在Descriptor中,我們重寫了assignFromBits()和asBits用于協議字段的提取與數據流的的封裝.如此,我們在使用時即可在代碼使用時使代碼里盡可能的簡潔明了:
在一個大型工程里,往往可能存在許多的協議定義,那么協議的提取與數據流封裝就往往需要許多這種assignFromBits()和asBits的重寫了,“繁重的”體力勞動。
在SpinalHDL 1.9.4版本中,引入了PackedBundle、PackedWordBundle兩個組件(之前的版本略有bug)。從而能夠避免這種重復的體力活。像上面的結構中,可以直接這么定義Descriptor數據類型:
caseclassDescriptor() extends PackedBundle { val host_addr=UInt(64bits).packFrom(0) val card_addr=UInt(64bits).packFrom(64) val length=UInt(14bits) //根據當前已使用的位域推斷其對應的位域 val sop=Bool().packFrom(128+16) val eop=Bool().packFrom(128+16+1) }
我們無需再override任何函數,僅需定義數據類型即可。在使用時:
通過unpack,可以從data_in中提取協議字段,通過packed方法,可以將協議字段按照位域封裝成數據流。
》PackedBundle
在PackedBundle中,為SpinalHDL中的基礎數據類型隱式擴展了DataPositionEnrich類。為其定義了用于位域綁定的函數:
def pack(range: Range)
def pack(range: Range, endianness: Endianness = LITTLE)
def packFrom(pos: Int)
def packTo(pos: Int)
通過這幾個函數,我們可以在使用時對定義的字段綁定位域。這里面在使用時更傾向于后面兩種方式。對于packTo與packFrom,下面的Descriptor描述方式和上面的Descriptor是等效的:
caseclassDescriptor() extends PackedBundle { val host_addr=UInt(64bits).packTo(63) val card_addr=UInt(64bits).packTo(127) val length=UInt(14bits) val sop=Bool().packFrom(128+16) val eop=Bool().packFrom(128+16+1) }
而通過PackedBundle中所提供的pack方法,可以用于將我們定義的數據類型封裝成數據流:
def packed: Bits
而對于從數據流中提取協議字段,則可以通過unpack方法:
def unpack(bits: Bits)
def unpack(bits: Bits, hi: Int, lo: Int)
第二個方法使用場景可能相對較少,感興趣的可以去看源代碼。
》PackedWordBundle
PackedWordBundle是在PackedBundle的基礎上擴展而來,從而能夠按照Word進行位域綁定,使用相對簡單,不再做額外贅述,參考例子:
》使用注意
對于PackedBundle、PackedWordBundle,其有種C語言位域結構體的味道,可以方便的定義位域,減少重復性的開發工作。不過其中有一點是其允許位域重復,如下所示:
caseclassDescriptor() extends PackedBundle { val host_addr=UInt(64bits).packTo(63) val card_addr=UInt(64bits).packTo(63) val length=UInt(14bits) val sop=Bool().packFrom(128+16) val eop=Bool().packFrom(128+16+1) }
將card_addr與host_addr綁定到相同的位置是允許的,在進行pack時由于Last Valid Assignment Win,host_addr將不會被使用。故在使用時需注意別重復綁定。
審核編輯:彭菁
-
數據
+關注
關注
8文章
7048瀏覽量
89073 -
封裝
+關注
關注
126文章
7916瀏覽量
143003 -
代碼
+關注
關注
30文章
4790瀏覽量
68650
原文標題:位域一鍵提取/封裝
文章出處:【微信號:Spinal FPGA,微信公眾號:Spinal FPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論