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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
// SPDX-License-Identifier: Apache-2.0
package chisel3
import chisel3.internal._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
object when {
/** Create a `when` condition block, where whether a block of logic is
* executed or not depends on the conditional.
*
* @param cond condition to execute upon
* @param block logic that runs only if `cond` is true
*
* @example
* {{{
* when ( myData === 3.U ) {
* // Some logic to run when myData equals 3.
* } .elsewhen ( myData === 1.U ) {
* // Some logic to run when myData equals 1.
* } .otherwise {
* // Some logic to run when myData is neither 3 nor 1.
* }
* }}}
*/
def apply(
cond: => Bool
)(block: => Any
): WhenContext = {
new WhenContext(Some(() => cond), block, 0, Nil)
}
/** Returns the current `when` condition
*
* This is the conjunction of conditions for all `whens` going up the call stack
* {{{
* when (a) {
* when (b) {
* when (c) {
* }.otherwise {
* when.cond // this is equal to: a && b && !c
* }
* }
* }
* }}}
*/
def cond: Bool = {
val whens = Builder.whenStack
whens.foldRight(true.B) {
case (ctx, acc) => acc && ctx.localCond
}
}
}
/** A WhenContext may represent a when, and elsewhen, or an
* otherwise. Since FIRRTL does not have an "elsif" statement,
* alternatives must be mapped to nested if-else statements inside
* the alternatives of the preceeding condition. In order to emit
* proper FIRRTL, it is necessary to keep track of the depth of
* nesting of the FIRRTL whens. Due to the "thin frontend" nature of
* Chisel3, it is not possible to know if a when or elsewhen has a
* succeeding elsewhen or otherwise; therefore, this information is
* added by preprocessing the command queue.
*/
final class WhenContext private[chisel3] (
cond: Option[() => Bool],
block: => Any,
firrtlDepth: Int,
// For capturing conditions from prior whens or elsewhens
altConds: List[() => Bool]) {
@deprecated("Use when(...) { ... }, this should never have been public", "Chisel 3.4.2")
def this(cond: Option[() => Bool], block: => Any, firrtlDepth: Int = 0) =
this(cond, block, firrtlDepth, Nil)
private var scopeOpen = false
/** Returns the local condition, inverted for an otherwise */
private[chisel3] def localCond: Bool = {
val alt = altConds.foldRight(true.B) {
case (c, acc) => acc & !c()
}
cond
.map(alt && _())
.getOrElse(alt)
}
/** This block of logic gets executed if above conditions have been
* false and this condition is true. The lazy argument pattern
* makes it possible to delay evaluation of cond, emitting the
* declaration and assignment of the Bool node of the predicate in
* the correct place.
*/
def elsewhen(
elseCond: => Bool
)(block: => Any
): WhenContext = {
new WhenContext(Some(() => elseCond), block, firrtlDepth + 1, cond ++: altConds)
}
/** This block of logic gets executed only if the above conditions
* were all false. No additional logic blocks may be appended past
* the `otherwise`. The lazy argument pattern makes it possible to
* delay evaluation of cond, emitting the declaration and
* assignment of the Bool node of the predicate in the correct
* place.
*/
def otherwise(block: => Any): Unit =
new WhenContext(None, block, firrtlDepth + 1, cond ++: altConds)
def active: Boolean = scopeOpen
@deprecated(
"Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead",
"Chisel 3.5"
)
def active(dummy: Int*): Boolean = active
/*
*
*/
if (firrtlDepth > 0) { pushCommand(AltBegin()) }
cond.foreach(c => pushCommand(WhenBegin(c().ref)))
Builder.pushWhen(this)
try {
scopeOpen = true
block
} catch {
case _: scala.runtime.NonLocalReturnControl[_] =>
throwException(
"Cannot exit from a when() block with a \"return\"!" +
" Perhaps you meant to use Mux or a Wire as a return value?"
)
}
scopeOpen = false
Builder.popWhen()
cond.foreach(_ => pushCommand(WhenEnd(firrtlDepth)))
if (cond.isEmpty) { pushCommand(OtherwiseEnd(firrtlDepth)) }
}
|