## 赋值(Assignments) ### 一、赋值(Assignments) SpinalHDL中有多个赋值运算: | 符号 | 描述 | | :---: | :------------------------------------------------------------------------------------------: | | `:=` | 标准赋值, 等价于VHDL/Verilog中的`<=`;对变量的最后一次赋值有效;直到下一个仿真周期数据才更新 | | `\=` | 等价于VHDL中的`:=`和Verilog中的`=`, 数据会立即更新 | | `<>` | 自动地链接两个信号或相同类型的两个Bundle, 信号的方向通过in/out推断(行为上更像`:=`) | ```Scala //因为硬件的并发性, `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 ``` 也支持打包赋值, 把多个信号用()打包来赋值: ```Scala 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)信号。 ```Scala 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并把环路路径打印出来。