规则(Rules)
一、简介(Introduction)
SpinalHDL背后的语义学很重要, 学会语义你就能理解在这些情景背后到底发生了什么, 并且如何去控制它。
这些语义通过以下几条规则定义:
信号和寄存器互相并行地执行(正如VHDL和Verilog, 硬件并发特点)
对组合逻辑的赋值很像是写出它何时是true的表达式
对寄存器的赋值很像是写出在时钟域下施加什么信号的规则
对于每个信号, 以最后一个赋值的为准
每个信号和寄存器都能以OOP方式在硬件描述细化期间作为对象控制
二、并行性(Concurrency)
你给每个组合逻辑或寄存器赋值的顺序对其硬件行为没有影响。
例如, 以下两段代码完全等价:
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
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)
如果组合逻辑信号或寄存器多次被赋值, 最后一次赋值有效。
例如:
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
):
val inc, clear = Bool() //定义两个组合逻辑信号/线类型
val counter = Reg(UInt(8 bits)) //定义8 bit寄存器
when(inc) {
counter := counter + 1
}
when(clear) {
counter := 0 //如果inc和clear都为真, 该赋值有效
}
你可以通过用赋值给counter
的函数混合之前的例子来实现完全一致的函数性:
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
}
你也可以把条件集成到函数内:
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)
并且也可以描述应该给函数赋什么值:
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。