赋值(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并把环路路径打印出来。