risc-v中文社区

 找回密码
 立即注册
查看: 1056|回复: 0

[原创] SpinalHDL—Function

[复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2022-6-6 16:14:27 | 显示全部楼层 |阅读模式
聊一聊SpinalHDL中Function的使用。阅读本文之前建议先阅读文末往期精选中的两篇文章。
不一样的“function”

    诸君尽知,我们在写Verilog/SystemVerilog电路描述时,可以将部分功能抽象到function 中。然则,在Verilog/SystemVerilog中,function只能用于描述组合逻辑,因而我们稍微复杂的时序逻辑的封装都必须采用module的形式了。
    而在SpinalHDL里,我们的所有语法都是基于Scala的,而且我们的电路描述一般都在class中。熟悉面向对象设计方法的小伙伴都知道,我们可以在class中定义方法。那么同样地,我们可以在这里用Function来抽象定义电路。不同于Verilog/SystemVerilog中的方法,在这里我们定义Function可以:
我们可以在Function 中定义寄存器、组合电路,Area甚至Component。

所有的参数都是以引用的形式进行传递,方便我们在函数中进行操作。

    一言以蔽之,我们在Function中可以写任何符合语法规范的电路结构。我们可以将一个总线作为参数传给function,然后在function内定义寄存器读写操作。我们也可以返回Component、Bus、甚至任何符合Scala 语法规范的东西。

    在Spinal HDL中,你会看到大量的实现是基于function来实现的。

按照OOP思维定义硬件

    在面向对象的设计思想里,我们会将一个组件及其功能定义在一个class中。这里以我们之前所描述的加法电路为例。在电路描述里我们定义了一个sumPort类:

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)
  }
}
    为了实现一个加法的功能,我们要么定义了一个Component、要么定义了一个Area来实现加法功能。而从面向对象的设计思维里,这个加法实现本应是sumPort本身应该具备的功能,因而我们可以在sumPort中定义一个方法用于实现sumPort的加法:

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)
  }

  def sumCal={
    sum:=RegNext(dataIn.translateWith(dataIn.data2+dataIn.data1))
  }
}
    这里,我们为sumPort定义了一个sumCal方法用于实现加法(加一级寄存器延迟)。这样我们无需定义额外的Component、Area即可实现加法功能调用:

class addInst4(dataWidth:Int) extends Component{
  val io=new Bundle{
    val sumport0=slave(sumPort(dataWidth))
    val sumport1=slave(sumPort(dataWidth))
  }
  io.sumport0.sumCal
  io.sumport1.sumCal
}
美中不足

    借助functin,我们可以很方便的在硬件电路描述里使用OOP的软件思维,然而目前有一点尚美中不足。考虑下面的电路描述:

class funcTest()extends Component{
  val io=new Bundle{
    val data0=in UInt(8 bits)
    val data1=in UInt(8 bits)
    val sum=out UInt(8 bits)
  }
  def sum(data0:UInt,data1:UInt):UInt={
    val sum=Reg( UInt(8 bits))
    sum:=data0+data1
    sum
  }
  io.sum:=sum(io.data0,io.data1)
}
     这里我们定义了一个sum的函数来实现加法功能,而在sum函数里我们又定义了一个sum变量寄存器类型。生成Verilog时代码是这般的:

module funcTest (
  input      [7:0]    io_data0,
  input      [7:0]    io_data1,
  output     [7:0]    io_sum,
  input               clk,
  input               reset
);
  reg        [7:0]    _zz_1;

  assign io_sum = _zz_1;
  always @ (posedge clk) begin
    _zz_1 <= (io_data0 + io_data1);
  end
endmodule
    可以发现,我们在sum函数中定义的sum变量并没有在生成的Verilog中保存下来。

        SpinalHDL目前对function中定义的变量在生成Verilog/SystemVerilog时不会保留原名,而以__zz_*的形式替代。


    当然也可以在function 中定义Area(Area中的变量名会保留)。

    关于function的进阶例子可以参照下述连接:

    https://gitee.com/peasent/Spinal ... a/workshop/function

本帖来源微信公从号:Spinal FPGA

网页地址:链接

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



Archiver|手机版|小黑屋|risc-v中文社区

GMT+8, 2024-4-24 06:28 , Processed in 0.014462 second(s), 17 queries .

risc-v中文社区论坛 官方网站

Copyright © 2018-2021, risc-v open source

快速回复 返回顶部 返回列表