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