在編寫Verilog代碼時最痛苦的事情便是例化模塊時端口的連接,這時候的你我便成了連線工程師,本節(jié)就在SpinalHDL中如何像軟件調(diào)用方法那樣優(yōu)雅地例化端口進(jìn)行探討。
習(xí)慣了寫Verilog的小伙伴們在做大型工程時是否有遇到過連續(xù)數(shù)天時間化身“連線工程師”去例化模塊、為端口賦值連接的場景(關(guān)鍵是這些工作量老板他也不認(rèn))。盡管在SystemVerilog中提供了Interface接口的概念,但是從事FPGA的小伙伴都清楚無論是Xilinx的Vivado還是Intel Quartus雖然支持SystemVerilog但遠(yuǎn)沒有做到像軟件代碼編輯器那般做到自動聯(lián)想與提示。最近分析一個Intel的大型源碼工程其中用到了大量的SystemVerilog中的interface及struct,但自動關(guān)聯(lián)提示做的真是一團(tuán)糟,導(dǎo)致閱讀體驗真是差的一匹…… 本文以一個簡單的加法器的例子來看如何在SpinalHDL中如何避免成為連線工程師。 加法器端口列表如下所示:端口名方向位寬說明
valid_ininput1輸入有效標(biāo)志
data1input8輸入數(shù)據(jù)
data2input8輸入數(shù)據(jù)
sumoutput8和
sum_validoutput1和有效標(biāo)志
初階
剛開始接觸SpinalHDL時這個加法器我們可能會這么來寫:
class add(dataWidth:Int) extends Component{ val validIn=in Bool() val data1=in UInt(dataWidth bits) val data2=in UInt(dataWidth bits) val sum=out UInt(dataWidth bits) val sumValid=out Bool() sum:=RegNextWhen(data1+data2,validIn) sumValid:=RegNext(validIn,F(xiàn)alse)}
這里針對端口的實現(xiàn)形式和我們在Verilog中的方式基本相同。那么當(dāng)我們在例化這個模塊時,我們可能會這么來寫:
class addInst(dataWidth:Int) extends Component { val io=new Bundle{ val validIn_0=in Bool() val data1_0=in UInt(dataWidth bits) val data2_0=in UInt(dataWidth bits) val sum_0=out UInt(dataWidth bits) val sumValid_0=out Bool()
val validIn_1=in Bool() val data1_1=in UInt(dataWidth bits) val data2_1=in UInt(dataWidth bits) val sum_1=out UInt(dataWidth bits) val sumValid_1=out Bool() } val add0=new add(dataWidth) val add1=new add(dataWidth) add0.validIn《》io.validIn_0 add0.data1《》io.data1_0 add0.data2《》io.data2_0 add0.sum《》io.sum_0 add0.sumValid《》io.sumValid_0 add1.validIn《》io.validIn_1 add1.data1《》io.data1_1 add1.data2《》io.data2_1 add1.sum《》io.sum_1 add1.sumValid《》io.sumValid_1}
這里例化了兩個加法器,可以看到,這里如同我們寫Verilog代碼般一根根連線,當(dāng)有眾多模塊需要去例化時還是蠻痛苦的。
中階
在SystemVerilog中提供了Interface的概念用于封裝接口,在SpinalHDL中,我們可以借助軟件面向?qū)ο蟮乃枷氚呀涌诮o抽象出來:
case class sumPort(dataWidth:Int=8) extends Bundle with IMasterSlave{ case class dataPort(dataWidth:Int=8) extends Bundle{ val data1=UInt(dataWidth bits) val data2=UInt(dataWidth bits) } val dataIn=Flow(dataPort(dataWidth)) val sum=Flow(UInt(dataWidth bits))
override def asMaster(): Unit = { master(dataIn) slave(sum) }}
這里我們將加法器的端口抽象成sumPort端口。其中包含兩個Flow類型:dataIn、sum。并聲明當(dāng)作為master端口時dataIn為master、sum為slave。這樣,我們的加法器便可以這么來寫:
case class add2(dataWidth:Int=8)extends Component{ val io=new Bundle{ val sumport=slave(sumPort(dataWidth)) } io.sumport.sum.payload:=RegNextWhen(io.sumport.dataIn.data1+io.sumport.dataIn.data2,io.sumport.dataIn.valid) io.sumport.sum.valid:=RegNext(io.sumport.dataIn.valid,F(xiàn)alse)}
而我們在例化時,便可以簡潔地例化:
class addInst1(dataWidth:Int) extends Component{ val io=new Bundle{ val sumport0=slave(sumPort(dataWidth)) val sumport1=slave(sumPort(dataWidth)) } val addInst_0=add2(dataWidth) val addInst_1=add2(dataWidth) io.sumport0《》addInst_0.io.sumport io.sumport1《》addInst_1.io.sumport}
如此我們便能簡潔地例化加法器。雖然這里地做法思想和SystemVerilog中地思想基本一致,但好處是我們能夠在IDEA中像閱讀軟件代碼那般快速地跳轉(zhuǎn)和定位,相較于廠商工具中那樣分析工程地痛苦實在是好太多。
高階
在中階例,我們采用了類似SystemVerilog中Interface及struct概念,但可以發(fā)現(xiàn),我們這里依舊存在連線行為。一個模塊例化一次要連線一次,要例化N次還是要……
在軟件代碼中,調(diào)用一個方法或者模塊往往一行代碼了事:聲明調(diào)用函數(shù)并將參數(shù)放在括號列表里。那么在這里,我們能否像軟件調(diào)用那樣一行代碼搞定呢?
可以的!由于SpinalHDL是基于Scala的,因此我們可以將端口列表當(dāng)成參數(shù)列表來傳遞。這里我們先為我們的加法器定義一個伴生對象:
object add2{ def apply(dataWidth: Int,port Unit = { val addInst=new add2(dataWidth) addInst.io.sumport《》port }}
這里我們?yōu)榧臃ㄆ鱝dd2定義了一個伴生對象(伴生對象聲明為object,名字與類名相同)。并在其中定義了一個apply方法,傳入兩個參數(shù):位寬dataWidth及端口port,并在apply實現(xiàn)中完成模塊例化及端口連接(一次連線,終身使用)。隨后我們在例化時便可以像軟件調(diào)用方法那樣例化模塊了:
class addInst1(dataWidth:Int) extends Component{ val io=new Bundle{ val sumport0=slave(sumPort(dataWidth)) val sumport1=slave(sumPort(dataWidth)) } add2(dataWidth,io.sumport0) add2(dataWidth,io.sumport0)}
一行代碼搞定一個模塊的一次例化和端口連接!
原文標(biāo)題:SpinalHDL—像軟件調(diào)用方法般例化模塊
文章出處:【微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
責(zé)任編輯:haq
-
軟件
+關(guān)注
關(guān)注
69文章
4944瀏覽量
87491 -
Verilog
+關(guān)注
關(guān)注
28文章
1351瀏覽量
110100
原文標(biāo)題:SpinalHDL—像軟件調(diào)用方法般例化模塊
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
內(nèi)部端口和外部端口怎么填
外部端口和內(nèi)部端口是什么意思
控制端口和數(shù)據(jù)端口怎么區(qū)別
ad中端口的幾種類型
求助各位關(guān)于Verilog當(dāng)中模塊例化、端口與引腳 的問題
PLC輸入端口和輸出端口的工作原理
在嵌入式設(shè)計中擴(kuò)展串行端口的入門知識
![<b class='flag-5'>在</b>嵌入式設(shè)計<b class='flag-5'>中</b>擴(kuò)展串行<b class='flag-5'>端口</b>的入門知識](https://file1.elecfans.com/web2/M00/D2/45/wKgaomYjGnmAQF-3AADqKe7Rp-Y977.png)
verilog雙向端口的使用
優(yōu)雅停機(jī)是什么?SpringBoot+Nacos+k8s實現(xiàn)優(yōu)雅停機(jī)
![<b class='flag-5'>優(yōu)雅</b>停機(jī)是什么?SpringBoot+Nacos+k8s實現(xiàn)<b class='flag-5'>優(yōu)雅</b>停機(jī)](https://file1.elecfans.com/web2/M00/C0/3D/wKgZomXUCEmAb_r5AAALd2ad_bI181.jpg)
評論