summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/core/When.scala
blob: 196e7903ce13215e2f5c1a5637f6120d71307f41 (plain)
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
// See LICENSE for license details.

package chisel3.core

import scala.language.experimental.macros

import chisel3.internal._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.{SourceInfo}

object when {  // scalastyle:ignore object.name
  /** 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 === UInt(3) ) {
    *   // Some logic to run when myData equals 3.
    * } .elsewhen ( myData === UInt(1) ) {
    *   // 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: => Unit)(implicit sourceInfo: SourceInfo): WhenContext = {
    new WhenContext(sourceInfo, cond, !cond, block)
  }
}

/** Internal mechanism for generating a when. Because of the way FIRRTL
  * commands are emitted, generating a FIRRTL elsewhen or nested whens inside
  * elses would be difficult. Instead, this keeps track of the negative of the
  * previous conditions, so when an elsewhen or otherwise is used, it checks
  * that both the condition is true and all the previous conditions have been
  * false.
  */
final class WhenContext(sourceInfo: SourceInfo, cond: Bool, prevCond: => Bool, block: => Unit) {
  /** This block of logic gets executed if above conditions have been false
    * and this condition is true.
    */
  def elsewhen (elseCond: Bool)(block: => Unit)(implicit sourceInfo: SourceInfo): WhenContext = {
    new WhenContext(sourceInfo, prevCond && elseCond, prevCond && !elseCond, block)
  }

  /** This block of logic gets executed only if the above conditions were all
    * false. No additional logic blocks may be appended past the `otherwise`.
    */
  def otherwise(block: => Unit)(implicit sourceInfo: SourceInfo): Unit =
    new WhenContext(sourceInfo, prevCond, null, block)

  pushCommand(WhenBegin(sourceInfo, cond.ref))
  block
  pushCommand(WhenEnd(sourceInfo))
}