十二 · 2021年11月04日

SpinalHDL—if向左、when向右

在初学SpinalHDL时,最困扰的一点便是我的代码里哪部分是在描述的电路对象,哪部分是借助高级语言来方便地描述电路。本文借助最基础的if、when来加深对此的理解。

if&when

在阅读本文之前,可先翻看往期文章《SpinalHDL—柳暗花明又一村》

这里拿小练习(三)中的例子来作为举例:

case class example3_1(sigNum:Int) extends Component{
  val io=new Bundle{
    val dataInVec=in Vec(UInt(8 bits),sigNum)
    val dataOutVec=out Vec(UInt(8 bits),sigNum)
  }
  val _=new Area{
    for(index<-0 until sigNum){
      if(index<sigNum/2){
        when(io.dataInVec(index).msb){
          io.dataOutVec(index):=io.dataInVec(index).asSInt.abs+1
        }otherwise{
          io.dataOutVec(index):=io.dataInVec(index)-1
        }
      } else {
        when(io.dataInVec(index).msb){
          io.dataOutVec(index):=io.dataInVec(index)+1
        }otherwise {
          io.dataOutVec(index):=io.dataInVec(index)+2
        }
      }
    }
  }
}
object example3App extends App{
  SpinalSystemVerilog(example3_1(2))
}

这里要实现的逻辑是输入端口数据类型为无符号数,转换为有符号数处理,前一半若小于0,则取绝对值+1,否则减1.后一半若小于0,则加1,否则+2。

这里我们用到了for、if、when三个关键词,for、if是scala原生的、when则是SpinalHDL中定义的。那么这里什么时候该用if、什么时候该用when、for又会生成什么样的电路对象呢?

从scala到Verilog转换那点事儿

在开始分析之前,先定三个准则:

  1. 只有SpinalHDL中定义的对象类型才会对应电路结构。
  2. 只有SpinalHDL中定义的对象类型才会对应电路结构。
  3. 只有SpinalHDL中定义的对象类型才会对应电路结构。

好了,现在回到起点。的确,我们是采用SpinalHDL来描述符电路,但是我们写的是什么?是Scala,是一个非常标准的软件语言!而SpinalHDL只不过是作为一个Scala的Lib而已。那么也就意味着:

我们将SpinalHDL转换为Verilog描述的过程实际上只是执行了一个调用了SpinalHDL lib扩展的普通的Scala程序而已。

既然我们的转换过程实质上是一个软件程序执行过程,那么我们可以程序的执行过程里当作一出好戏,这里面的角色有:

  • 原始Scala程序输入:张三。
  • Scala程序执行:李四。
  • RTL代码代写者:王五。     

好了,当张三把一段使用了SpinalHDL Lib的Scala程序写好后(这里假定sigNum=2)编译成二进制可执行程序交给Scala程序执行者李四后李四开始去执行这段代码。

李四找到程序入口,发现这里例化了一个example3_1的对象,他会在初始化这个对象时去分析example3_1中都包含了哪些元素。

  • 首先,李四看到了一个为Bundle类型的变量io,由于Bundle是SpinalHDL库中定义的东东声明模块端口,因此他拿了个小本本主义记下了:

    端口声明:
    val io=new Bundle{

      val dataInVec=in Vec(UInt(8 bits),2)
      val dataOutVec=out Vec(UInt(8 bits),2)
    }
    
  • 随后,在匿名变量“_”对应的Area中,李四看到了一个for循环(循环次数为2),李四只知道for循环是需要一遍一遍地看的,因此李四开始for循环展开理解这段程序:

第一轮阅读(index=0),看到了if…else结构,此时index<sigNum/2,李四选择去看if分支,他看到了一段SpinalHDL中定义的对象的描述,因此又在小本本上写下:

端口声明:
val io=new Bundle{
    val dataInVec=in Vec(UInt(8 bits),2)
    val dataOutVec=out Vec(UInt(8 bits),2)
  }
逻辑描述
when(io.dataInVec(index).msb){
  io.dataOutVec(0):=io.dataInVec(0).asSInt.abs+1
}otherwise{
  io.dataOutVec(0):=io.dataInVec(0)-1
}

好了,第一轮阅读结束了,接下来要进入下一轮了阅读了,此时index<index/2不成立,因此李四进入了else分支,而在else分支里仍是SpinalHDL中定义的些语法,于是他又一股脑将这些东西记录在小本本上:

端口声明:
val io=new Bundle{
    val dataInVec=in Vec(UInt(8 bits),2)
    val dataOutVec=out Vec(UInt(8 bits),2)
  }
逻辑描述
when(io.dataInVec(index).msb){
  io.dataOutVec(0):=io.dataInVec(0).asSInt.abs+1
}otherwise{
  io.dataOutVec(0):=io.dataInVec(0)-1
}
when(io.dataInVec(1).msb){
  io.dataOutVec(1):=io.dataInVec(1)+1
}otherwise {
  io.dataOutVec(1):=io.dataInVec(1)+2
}

好了,至此李四完成了他所有的工作,随后李四将他的小本本交给王五让王五去照着本子上的内容去生成Verilog去了。

王五对Scala不熟,但他对SpinalHDL中的语法很熟悉,知道哪个关键词对应Verilog中哪个语句(Verilog中可综合语法也就无非那么几个:if/else、case、always等)。当王五拿到这个本子后很快就将对应的Verilog电路描述写好交给我们了。  

写在最后

最后,依旧拿别人教我的分享给诸君,理解之后,我们写电路描述就像开了副本一样快速而方便了(摸鱼别被老板看见🤓🤓🤓):

END

作者:玉骐
原文链接:https://mp.weixin.qq.com/s/JQKOWfXbTCt0cJya7qTpSA
微信公众号:
 title=

推荐阅读

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