赋值(Assignments)

一、赋值(Assignments)

SpinalHDL中有多个赋值运算:

符号 描述
:= 标准赋值, 等价于VHDL/Verilog中的<=;对变量的最后一次赋值有效;直到下一个仿真周期数据才更新
\= 等价于VHDL中的:=和Verilog中的=, 数据会立即更新
<> 自动地链接两个信号或相同类型的两个Bundle, 信号的方向通过in/out推断(行为上更像:=)
//因为硬件的并发性, `a`的值一直是1
val a, b, c = UInt(4 bits)
a := 0
b := a
a := 1  //a := 1 "wins"
c := a

var x UInt(4 bits)
val y, z = UInt(4 bits)
x := 0
y := x      //y读到0
x \= x + 1
z := x      //z读到1

//自动连接两个UART接口
uartCtrl.io.uart <> io.uart

也支持打包赋值, 把多个信号用()打包来赋值:

val a, b, c = UInt(4 bits)
val d       = UInt(12 bits)
val e       = Bits(10 bits)
val f       = SInt(2 bits)
val g       = Bits()

(a, b, c) := B(0, 12 bits)
(a, b, c) := d.asBits
(a, b, c) := (e, f).asBits
(a, b, c) := (a, b, c, e, f).asBits

在SpinalHDL中, 理解信号的本质(combinational/sequential)是由它的声明定义的, 并不是赋值的方式。所有的数据类型例化都会定义一个组合信号, 用Reg(...)包装的数据类型例化会定义时序(registered)信号。

val a = UInt(4 bits)        //定义组合信号
val b = Reg(UInt(4 bits))   //定义寄存器信号
val c = Reg(UInt(4 bits)) init(0)   //定义复位为0的寄存器信号

二、位宽检查(Width checking)

SpinalHDL会检查赋值的左右两侧bit宽度是否一致。有多种方式能够去适应给定的Bit向量(Bits, UInt, SInt):

改变尺寸的方法 描述
x:=y.resized 用y的改变大小后的复制赋值给x, 改变的值会根据匹配的x自适应
x:=y.resize(newWidth) 用y的改变大小后的复制赋值给x, 尺寸是手工计算的

有一个SpinalHDL自动改变值的位宽的例子:

赋值 问题 SpinalHDL行为
myUIntOf_8bit:=U(3) U(3)创建2 bits的UInt, 不能匹配左侧8 bits的位宽 因为推断出U(3)的bit数较小, SpinalHDL自动改变尺寸

三、组合逻辑环路(Combinatorial loops)

SpinalHDL会检查在设计中有没有组合逻辑环路(Latches), 如果检查到, SpinalHDL会提示error并把环路路径打印出来。