You're reading the documentation for a development version.
For the latest stable release version, please have a look at master.

When/Switch/Mux

When

As in VHDL and Verilog, signals can be conditionally assigned when a specified condition is met:

when(cond1) {
  // Execute when cond1 is true
}.elsewhen(cond2) {
  // Execute when (not cond1) and cond2
}.otherwise {
  // Execute when (not cond1) and (not cond2)
}

Warning

If the keyword otherwise is on the same line as the closing bracket } of the when condition, no dot is needed.

when(cond1) {
    // Execute when cond1 is true
} otherwise {
    // Execute when (not cond1) and (not cond2)
}

But if .otherwise is on another line, a dot is required:

when(cond1) {
    // Execute when cond1 is true
}
.otherwise {
    // Execute when (not cond1) and (not cond2)
}

Switch

As in VHDL and Verilog, signals can be conditionally assigned when a signal has a defined value:

switch(x) {
  is(value1) {
    // Execute when x === value1
  }
  is(value2) {
    // Execute when x === value2
  }
  default {
    // Execute if none of precedent conditions met
  }
}

is clauses can be factorized by separating them with a comma is(value1, value2).

Example

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

is equivalent to

switch(aluop) {
  is(ALUOp.add, ALUOp.slt, ALUOp.sltu) {
      immediate := instruction.immI.signExtend
  }
  is(ALUOp.sll, ALUOp.sra) {
      immediate := instruction.shamt
  }
}

Local declaration

It is possible to define new signals inside a when/switch statement:

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
}

Note

SpinalHDL checks that signals defined inside a scope are only assigned inside that scope.

Mux

If you just need a Mux with a Bool selection signal, there are two equivalent syntaxes:

Syntax

Return

Description

Mux(cond, whenTrue, whenFalse)

T

Return whenTrue when cond is True, whenFalse otherwise

cond ? whenTrue | whenFalse

T

Return whenTrue when cond is True, whenFalse otherwise

val cond = Bool
val whenTrue, whenFalse = UInt(8 bits)
val muxOutput  = Mux(cond, whenTrue, whenFalse)
val muxOutput2 = cond ? whenTrue | whenFalse

Bitwise selection

A bitwise selection looks like the VHDL when syntax.

Example

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

Also, if all possible values are covered in your mux, you can omit the default value:

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

Alternatively, if the uncovered values are not important, they can be left unassigned by using muxListDc

muxLists(...) is another bitwise selection which takes a sequence of tuples as input. Below is an example of dividing a Bits of 128 bits into 32 bits:

../../_images/MuxList.png
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)