十二 · 2022年01月30日

彩——看blackBox的inline功能

聊一聊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
微信公众号:
 title=

推荐阅读

更多SpinalHDL技术干货请关注Spinal FPGA专栏。
推荐阅读
关注数
1581
内容数
133
用SpinalHDL提升生产力
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息