聊一聊SpinalHDL 1.6.1引入的blackbox inline功能。
BlackBox
在之前的文章中,曾介绍过如何封装兼容别人的RTL代码:SpinalHDL——集成你的RTL代码
整体的思路还是简洁明了的,相信读完后照着做很快就能上手。这对于保持设计的兼容性及混合编程都有极大的便利。
在上面的blackbox的使用方式里,封装成blackbox的Verilog代码和SpinalHDL代码是分开维护的,作为开发使用没有什么问题,但如果你是作为一个第三方IP提供者,像之前文章提到的:“IP”库生成
在这种场景下,如果lib中存在blackbox那么在封装成jar包时并不会把Verilog文件给包含进去,这对于对外提供和交付则不是那么便利。
不过,在SpinalHDL 1.6.1版本中,提供了一个inline功能,用于将blackbox“真的”封装进SpinalHDL中。
setInlineVerilog
在BlackBox的定义里,新增了两个方法:
def setInlineVerilog(str : String) : Unit = setInline(new BlackBoxImpl{
override def getVerilog() = str
})
def setInlineVhdl(str : String) : Unit = setInline(new BlackBoxImpl{
override def getVhdl() = str
})
其采用的策略是将Verilog代码封装成字符串。最后包含到BlackBox中。这里给出一个example:
class adder(width: Int) extends BlackBox {
addGeneric("WIDTH", width)
val io = new Bundle {
val ain = in UInt (width bits)
val bin = in UInt (width bits)
val add_out = out UInt (width bits)
}
noIoPrefix()
// setInline(adderImpl)
setInlineVerilog(
"""module adder #(
| parameter WIDTH = 16
|) (
| input [WIDTH-1:0] ain ,
| input [WIDTH-1:0] bin ,
| output reg [WIDTH-1:0] add_out
|);
|
|always @(*) begin
| add_out = ain + bin;
|end
|
|endmodule
""".stripMargin
)
}
case class blackBoxTest(width: Int) extends Component {
val io = new Bundle {
val ain = in UInt (width bits)
val bin = in UInt (width bits)
val add_out = out UInt (width bits)
}
val adderInst = new adder(width)
adderInst.io.ain <> io.ain
adderInst.io.bin <> io.bin
adderInst.io.add_out <> io.add_out
}
实现起来so easy。
更进一步
上面的方式已经很简洁明了,但有一点儿也许有点儿不爽,那就是难道我还要把已经写好的代码给手动再copy进来么,那未免也太不“优雅”了。
别忘了SpinalHDL是基于Scala的,有什么是软件解决不了的问题呢~:
import spinal.core._
import spinal.lib._
import scala.io.Source
class adder(width: Int) extends BlackBox {
addGeneric("WIDTH", width)
val io = new Bundle {
val ain = in UInt (width bits)
val bin = in UInt (width bits)
val add_out = out UInt (width bits)
}
noIoPrefix()
addRTLPath("./adder.sv")
def setRtlInLine() = {
val rtlContent = new StringBuilder()
for (rtlFile <- listRTLPath) {
val rtlHdl = Source.fromFile(rtlFile)
rtlContent ++= rtlHdl.mkString
rtlHdl.close()
}
setInline(new BlackBoxImpl {
override def getVerilog() = rtlContent.toString()
})
}
setRtlInLine()
}
case class blackBoxTest(width: Int) extends Component {
val io = new Bundle {
val ain = in UInt (width bits)
val bin = in UInt (width bits)
val add_out = out UInt (width bits)
}
val adderInst = new adder(width)
adderInst.io.ain <> io.ain
adderInst.io.bin <> io.bin
adderInst.io.add_out <> io.add_out
}
这里自定义了一个setRtlInLine的方法。我们在使用addRTLPath 时已经指定了blackbox的路径,那么这里我们仅需去解析我们的blackbox转换成字符串即可,通过调用setRtlInLine方法,即可得到我们的inline内容(当然某些场景下也可以将文件解析内容拿出来手动copy上去)~
作者:玉骐
原文链接:Spinal FPGA
微信公众号:
推荐阅读
更多SpinalHDL技术干货请关注Spinal FPGA专栏。