0%

2.3 Control Flow

2.3 Control Flow

‘:=’ Last Connect Semantics

It is possible to issue multiple connect statements to the same component. When this happens, the last statement wins.

1
2
3
4
5
6
7
8
9
10
class LastConnect extends Module {
val io = IO(new Bundle {
val in = Input(UInt(4.W))
val out = Output(UInt(4.W))
})
io.out := 1.U
io.out := 2.U
io.out := 3.U
io.out := 4.U // last statement wins
}

Chisel Conditional Logic

  • Actions taken in the bodies of the the three can be complex blocks and may contain nested when and allies.
  • when (chiselBoolType), if (scalaBooleanType)
1
2
3
4
5
6
7
when(chiselBoolType) {
// if (scalaBooleanType)
}.elsewhen(someOtherBooleanCondition) {
// else if
}.otherwise {
// else
}
  • Unlike Scala if, values are not returned by the blocks associated with when.
1
2
// error
val result = when(squareIt) { x * x }.otherwise { x }

We will discuss the solution to this in the Wires section.

Wire

Wire defines a circuit component that can appear on the right hand side or left hand side of a connect := operator.

1
val wire = Wire(Uint(12.W))

example

  • 4-Input Sort with Wires
image-20221221164557228 v2-cdda3f11c6efbc01577f5c29a9066772_b
  • Polynomial Circuit

Use Wire so that the $x^2$ computation appears only once in the module and so that there is a single connection to the output.

  • $x^2 - 2x + 1$
  • $2x^2 + 6x + 3$
  • $4x^2 - 10x -5$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Polynomial extends Module {
val io = IO(new Bundle {
val select = Input(UInt(2.W))
val x = Input(SInt(32.W))
val fOfX = Output(SInt(32.W))
})

val result = Wire(SInt(32.W))
val square = Wire(SInt(32.W))

square := io.x * io.x // $x^2$ computation appears only once

when(io.select === 0.U){
result := square - 2.S * io.x + 1.S
}.elsewhen(io.select === 1.U){
result := 2.S * square + 6.S * io.x + 3.S
}.otherwise{
result := 4.S * square - 10.S * io.x - 5.S
}

io.fOfX := result // there is a single connection to the output
}
  • Finite State Machine

Precedence: coffee > idea > pressure

image-20221221173650661

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// state map
def states = Map("idle" -> 0, "coding" -> 1, "writing" -> 2, "grad" -> 3)

// life is full of question marks
def gradLife (state: Int, coffee: Boolean, idea: Boolean, pressure: Boolean): Int = {
var nextState = states("idle")
if (state == states("idle")) {
if (coffee) { nextState = states("coding") }
else if (idea) { nextState = states("idle") }
else if (pressure) { nextState = states("writing") }
} else if (state == states("coding")) {
if (coffee) { nextState = states("coding") }
else if (idea || pressure) { nextState = states("writing") }
} else if (state == states("writing")) {
if (coffee || idea) { nextState = states("writing") }
else if (pressure) { nextState = states("grad") }
}
nextState
}

Module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// life gets hard-er
class GradLife extends Module {
val io = IO(new Bundle {
val state = Input(UInt(2.W))
val coffee = Input(Bool())
val idea = Input(Bool())
val pressure = Input(Bool())
val nextState = Output(UInt(2.W))
})

val idle :: coding :: writing :: grad :: Nil = Enum(4)

when (io.state === idle) {
when (io.coffee) { io.nextState := coding }
.elsewhen (io.idea) { io.nextState := idle}
.elsewhen (io.pressure) { io.nextState := writing}
.otherwise { io.nextState := idle}
}.elsewhen (io.state === coding) {
when (io.coffee) { io.nextState := coding }
.elsewhen (io.idea || io.pressure) { io.nextState := writing}
.otherwise { io.nextState := idle}
}.elsewhen (io.state === writing) {
when (io.coffee || io.idea) { io.nextState := writing }
.elsewhen (io.pressure) { io.nextState := grad}
.otherwise { io.nextState := idle}
}.otherwise { io.nextState := idle}
}