When/Switch/Mux

一、When

正如在VHDL和Verilog中, 信号可以根据条件是否符合来选择性地赋值:

when(cond1) {
    //当cond1真时执行操作
}.elsewhen(cond2) {
    //当cond1假但cond2真时执行操作
}.otherwise {
    //cond1和cond2同假时执行操作
}

注意:如果otherwise关键字和花括号的后半部分}在同一行, .可以省略

when(cond1) {
  //当cond1真时执行操作
} otherwise {
  //cond1和cond2同假时执行操作
}

但如果.otherwise在另一行, 需要.

when(cond1) {
  //当cond1真时执行操作
}
.otherwise {
  //cond1和cond2同假时执行操作
}

二、Switch

就像在VHDL和Verilog, 当信号得到固定值的时候可以条件执行运算:

switch(x) {
    is(value1) {
        //当x===value1执行
    }
    is(value2) {
        //当x===value2执行
    }
    default {
        //当之前的条件都没有符合执行
    }
}

is子句可以用is(value1, value2)这种逗号分割的方式书写。

举例:

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(ALU0p.add, ALU0p.slt, ALU0p.sltu) {
        immediate := instruction.immI.signExtend
    }
    is(ALU0p.sll, ALU0p.sra) {
        immediate := instruction.shamt
    }
}

三、本地声明(Local declaration)

也可以在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会检查信号是否只在该区域内被定义。

四、Mux

如果你只需要带有Bool选择信号的Mux, 有两种等价的语句形式:

语句 返回类型 描述
Mux(cond, whenTrue, whenFalse) T cond为真, 返回whenTrue, 否则返回whenFalse
cond ? whenTrue | whenFalse T cond为真, 返回whenTrue, 否则返回whenFalse
val cond = Bool
val whenTrue, whenFalse = UInt(8 bits)
val muxOutput   = Mux(cond, whenTrue, whenFalse)
val muxOutput2  = cond ? whenTrue | whenFalse

五、Bit级选择(Bitwise selection)

bit级的选择看起来像VHDL中when语句。

举例

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)
)

同样, 如果条件是完备的, 不需要些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)
)

或者, 如果未覆盖的值并不重要, 他们可以用muxListDc使其不赋值。

muxLists(...)是另一种bit级选择器, 该选择器以元组作为输入, 下图是一个把128 bits分割成32 bits的例子。

MuxList

val sel   = UInt(2 bits)
val data  = Bits(128 bits)

//把宽bit类型分成小块, 可以用mux:
val dataWord = sel.muxList(for (index <- until 4) yield (index, data(index*32+32-1 downto index*32)))

//一种书写更短的方式书写上述代码:
val dataWord = data.subdivideIn(32 bits)(sel)