## 规则(Rules) ### 一、简介(Introduction) SpinalHDL背后的语义学很重要, 学会语义你就能理解在这些情景背后到底发生了什么, 并且如何去控制它。 这些语义通过以下几条规则定义: + 信号和寄存器互相并行地执行(正如VHDL和Verilog, 硬件并发特点) + 对组合逻辑的赋值很像是写出它何时是true的表达式 + 对寄存器的赋值很像是写出在时钟域下施加什么信号的规则 + 对于每个信号, 以最后一个赋值的为准 + 每个信号和寄存器都能以OOP方式在硬件描述细化期间作为对象控制 ### 二、并行性(Concurrency) 你给每个组合逻辑或寄存器赋值的顺序对其硬件行为没有影响。 例如, 以下两段代码完全等价: ```Scala val a, b, c = UInt(8 bits) // Define 3 combinational signals c := a + b // c will be set to 7 b := 2 // b will be set to 2 a := b + 3 // a will be set to 5 ``` ```Scala val a, b, c = UInt(8 bits) // Define 3 combinational signals b := 2 // b will be set to 2 a := b + 3 // a will be set to 5 c := a + b // c will be set to 7 ``` 更加通俗来说, 当你用`:=`赋值操作符, 就好比给左侧的信号/寄存器一个新的数据产生规则。 ### 三、以最后赋值为准(Last valid assignment wins) 如果组合逻辑信号或寄存器多次被赋值, 最后一次赋值有效。 例如: ```Scala val x, y = Bool() //定义两个组合逻辑信号 val result = UInt(8 bits) //定义一个组合逻辑信号 result := 1 when(x) { result := 2 when(y) { result := 3 } } ``` 这会产生如下真值表: | x | y | => | 结果 | | :---: | :---: | :---: | :---: | | False | False | | 1 | | Fasle | True | | 1 | | True | False | | 2 | | True | True | | 3 | ### 四、Scala下的信号和寄存器的内在联系(Signal and register interactions with Scala)(OOP引用+函数) 在SpinalHDL中, 每个硬件单元通过类例化被建模。这意味着你可以用他们的引用使用例化, 例如把他们作为变量传递给函数。 以下例子实现了当`inc`为真时自增, 当`clear`为真时清零的寄存器(`clear`的优先级高于`inc`): ```Scala val inc, clear = Bool() //定义两个组合逻辑信号/线类型 val counter = Reg(UInt(8 bits)) //定义8 bit寄存器 when(inc) { counter := counter + 1 } when(clear) { counter := 0 //如果inc和clear都为真, 该赋值有效 } ``` 你可以通过用赋值给`counter`的函数混合之前的例子来实现完全一致的函数性: ```Scala val inc, clear = Bool() val counter = Reg(UInt(8 bits)) def setCounter(value: UInt): Unit = { counter := value } when(inc) { setCounter(counter + 1) } when(clear) { counter := 0 } ``` 你也可以把条件集成到函数内: ```Scala val inc, clear = Bool() val counter = Reg(UInt(8 bits)) def setCounterWhen(cond: Bool, value: UInt): Unit = { when(cond) { counter := value } } setCounterWhen(cond = inc, value = counter + 1) setCounterWhen(cond = clear, value = 0) ``` 并且也可以描述应该给函数赋什么值: ```Scala val inc, clear = Bool() val counter = Reg(UInt(8 bits)) def setSomethingWhen(something: UInt, cond: Bool, value: UInt): Unit = { when(cond) { something := value } } setSomethingWhen(something = counter, cond = inc, value = counter + 1) setSomethingWhen(something = counter, cond = clear, value = 0) ``` 之前所有的例子都和他们生成的RTL与SpinalHDL编译器方面严格等价, 这是因为SpinalHDL只关心Scala的运行和例化的对象, 不关心Scala语法本身。 换句话说, 从生成SpinalHDL/RTL生成器角度来说, 当你在Scala用函数生成电路, 这就好像函数是内联的。这对于Scala loop也同样适用, 因为他们将以展开的形式生成RTL。