1.1、When
与VHDL和Verilog一样,当满足指定条件时可以对信号进行有条件的赋值:
when(cond1) {
// Execute when cond1 is true
}.elsewhen(cond2) {
// Execute when (not cond1) and cond2
}.otherwise {
// Execute when (not cond1) and (not cond2)
}
如果关键字otherwise与when条件的右括号}在同一行,则不需要加点。如下:
when(cond1) {
// Execute when cond1 is true
} otherwise {
// Execute when (not cond1) and (not cond2)
}
但是如果.otherwise在另一行,需要加一个点:
when(cond1) {
// Execute when cond1 is true
}
.otherwise {
// Execute when (not cond1) and (not cond2)
}
1.2、Switch
与VHDL和Verilog类似,当一个信号有定义值时,可以对其进行条件赋值:
switch(x) {
is(value1) {
// Execute when x === value1
}
is(value2) {
// Execute when x === value2
}
default {
// Execute if none of precedent conditions met
}
}
可以通过用逗号将它们分开,从而得到一个子句,例如:is(value1, value2)。
1.2.1、实例
switch(aluop) {
is(ALUOp.add) {
immediate := instruction.immI.signExtend
}
is(ALUOp.slt) {
immediate := instruction.immI.signExtend
}
is(ALUOp.sltu) {
immediate := instruction.immI.signExtend
}
is(ALUOp.sll) {
immediate := instruction.shamt
}
is(ALUOp.sra) {
immediate := instruction.shamt
}
}
等效:
switch(aluop) {
is(ALUOp.add, ALUOp.slt, ALUOp.sltu) {
immediate := instruction.immI.signExtend
}
is(ALUOp.sll, ALUOp.sra) {
immediate := instruction.shamt
}
}
1.2.2、附加选项
默认情况下,如果一个 switch 包含了一个 default 语句,并且该switch 的所有可能逻辑值已经被 is 语句覆盖,则 SpinalHDL 将生成“UNREACHABLE DEFAULT STATEMENT”错误。您可以通过指定 switch(myValue, coverUnreachable = true) { … }
来取消此错误报告。
switch(my2Bits, coverUnreachable = false) {
is(0) { ... }
is(1) { ... }
is(2) { ... }
is(3) { ... }
default { ... } // This will be okay
}
此检查是基于逻辑值而非物理值进行的。例如,如果您有一个SpinalEnum(A,B,C)以独热码方式编码,SpinalHDL只会关心A、B、C这些值(“001”、“010”、“100”)。物理值如“000”、“011”、“101”、“110”和“111”将不被考虑。
默认情况下,如果给定的is语句多次提供相同的值,则SpinalHDL将生成“DUPLICATED ELEMENTS IN SWITCH IS(…) STATEMENT”的错误。
例如 is(42,42) { ... }
您可以通过指定switch(myValue, strict = true){ ... }
来取消此错误报告。然后,SpinalHDL将负责删除重复值。
switch(value, strict = false) {
is(0) { ... }
is(1,1,1,1,1) { ... } // This will be okay
is(2) { ... }
}
1.3、本地声明
可以在when/switch语句内定义新的信号:
val x, y = UInt(4 bits)
val a, b = UInt(4 bits)
when(cond) {
val tmp = a + b
x := tmp
y := tmp + 1
} otherwise {
x := 0
y := 0
}
SpinalHDL检查在作用域内定义的信号只能在该作用域内被赋值。
1.4、Mux
如果您只需要带有Bool
选择信号的 Mux,那么有两种等效的语法:
val cond = Bool()
val whenTrue, whenFalse = UInt(8 bits)
val muxOutput = Mux(cond, whenTrue, whenFalse)
val muxOutput2 = cond ? whenTrue | whenFalse
1.5、位选择
一个位选择看起来像VHDL的when语法。
1.5.1、实例
val bitwiseSelect = UInt(2 bits)
val bitwiseResult = bitwiseSelect.mux(
0 -> (io.src0 & io.src1),
1 -> (io.src0 | io.src1),
2 -> (io.src0 ^ io.src1),
default -> (io.src0)
)
mux会检查是否覆盖了所有可能的值,以防止产生锁存器。如果已经覆盖了所有可能的值,则不应添加default 语句:
val bitwiseSelect = UInt(2 bits)
val bitwiseResult = bitwiseSelect.mux(
0 -> (io.src0 & io.src1),
1 -> (io.src0 | io.src1),
2 -> (io.src0 ^ io.src1),
3 -> (io.src0)
)
muxList(...)
和muxListDc(...)
是备选的位选择器,它们将 tuples 或 mappings 序列作为输入。
在生成用例代码中,可以使用muxList
直接替换mux
,提供更易于使用的界面。它具有与mux相同的检查行为,要求完全覆盖并禁止在不需要时列出默认值。
如果未覆盖的值不重要,则可以使用muxtListDc
,并通过使用muxListDc
将其保留未分配状态。如果需要,则会添加一个默认情况。如果仿真过程中遇到X,则此默认情况将生成X's
。 muxListDc(...)
通常是通用代码的良好替代方案。
以下是将128位比特数分成32位比特数的示例:
val sel = UInt(2 bits)
val data = Bits(128 bits)
// Dividing a wide Bits type into smaller chunks, using a mux:
val dataWord = sel.muxList(for (index <- 0 until 4) yield (index, data(index*32+32-1 downto index*32)))
// A shorter way to do the same thing:
val dataWord = data.subdivideIn(32 bits)(sel)
通过 muxListDc 从可配置宽度向量中选择位的示例:
case class Example(width: Int = 3) extends Component {
// 2 bit wide for default width
val sel = UInt(log2Up(count) bit)
val data = Bits(width*8 bit)
// no need to cover missing case 3 for default width
val dataByte = sel.muxListDc(for(i <- 0 until count) yield (i, data(index*8, 8 bit)))
}