十二 · 2021年11月08日

拨开云雾—>是=还是:=

对于SpinalHDL电路描述,信号的赋值不免有些小伙伴带有些许迷茫,本篇抽丝剥茧,一块儿来梳理。

是val还是var?

先来看两个语法:

scala> val a=32
a: Int = 32

scala> a=23
<console>:12: error: reassignment to val
       a=23
        ^
scala> var b=32
b: Int = 32

scala> b=23
b: Int = 23

对于变量a,声明为val,在对其进行第二次赋值时发现会报错,而声明为var的变量则正常。在Scala里,对于val和var的定义:

  • **val:不可变变量类型。
  • var:可变变量类型

这似乎与我们在其他语言中所接触的有些冲突,变量是不可变的为什么还叫变量呢?Scala是一门函数式编程语言,而在函数式编程里,其所倡导的往往是变量的赋值仅有一次,对于其他地方不会对该变量进行重新赋值,这也是引入val类型的原因,颇有些C语言中const类型的意味。

而下面的语句:

scala> val c=Array.fill(3)(1)
c: Array[Int] = Array(1, 1, 1)

scala> c(0)=2

scala> c=Array.fill(2)(2)
<console>:12: error: reassignment to val
       c=Array.fill(2)(2)

这里变量c声明为val,其意味着c所指向的地址不可变更,但我们仍可以修改其指向的内容,这也正式为什么我们能对c(0)赋值,而无法再将c指向一个新声明的Array。

声明师=,赋值靠:=

有了上面的了解,再回到SpinalHDL电路描述里,我们在描述电路时,无论是寄存器还是Mem、这些都是电路对象,其声明有且仅应当只有一次,因而我们在定义变量时,往往这么来定义:

val a=Reg(UInt(8 bits))
val b=RegNext(a)

在Scala里一切皆为class,这里我们声明a为一个UInt对象、b为一个RegNext(a)对象,即这里声明a、b均为8比特的寄存器,而寄存器本身一旦定义了是不可变的,为val类型。想一想倘若一会儿将a声明为8bit寄存器,一会儿声明为9比特寄存器,像Verilog中这么写:

reg [7:0]a;
reg [8:0]a;

想必没人会在Verilog中这么来写吧。同理,在SpinalHDL里,我们声明一个电路对象时,自然是=。

虽然电路对象不可改,就像声明了a是8bit,其一定是8bit,但这8bit所代表的值是可以改变的!!!这也正是我们描述电路里的赋值。

SpinalHDL里为电路对象的赋值提供了三种形式:

image.png

我们是为电路对象所代表的值进行赋值,而不是改变电路对象本身(把电路对象指向另一个对象,想一想是否和上面Array的赋值有点儿类似),因而这里我们是不能用=(=在Scala中本身也是一个方法,是改变变量指向的位置,玩不可行),因而所要采用的是SpinalHDL中提供的:=或者\=来给电路对象所代表的含义进行赋值:

val a=Reg(UInt(8 bits))
val b=UInt(8 bits)
a:=4
b:=3

由于只有声明为Reg类型的变量才会被当成寄存器类型,这里即可放心使用“:=”。

小结

劝君莫惧Scala,我们在电路描述里用到的语法特性并不多,若有systemverilog的基础那么对于这类软件语言入门没那么可怕,毕竟又不是去转大数据不是么?

END

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

推荐阅读

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