@@ -23,23 +23,35 @@ object unless { // scalastyle:ignore object.name
23
23
/** Implementation details for [[switch ]]. See [[switch ]] and [[chisel3.util.is is ]] for the
24
24
* user-facing API.
25
25
*/
26
- class SwitchContext [T <: Bits ](cond : T ) {
27
- def is (v : Iterable [T ])(block : => Unit ) {
26
+ class SwitchContext [T <: Bits ](cond : T , whenContext : Option [ WhenContext ], lits : Set [ BigInt ] ) {
27
+ def is (v : Iterable [T ])(block : => Unit ): SwitchContext [ T ] = {
28
28
if (! v.isEmpty) {
29
- when (v.map(_.asUInt === cond.asUInt).reduce(_|| _)) {
30
- block
29
+ val newLits = v.map { w =>
30
+ require(w.isLit, " is conditions must be literals!" )
31
+ val value = w.litValue
32
+ require(! lits.contains(value), " all is conditions must be mutually exclusive!" )
33
+ value
31
34
}
35
+ // def instead of val so that logic ends up in legal place
36
+ def p = v.map(_.asUInt === cond.asUInt).reduce(_|| _)
37
+ whenContext match {
38
+ case Some (w) => new SwitchContext (cond, Some (w.elsewhen(p)(block)), lits ++ newLits)
39
+ case None => new SwitchContext (cond, Some (when(p)(block)), lits ++ newLits)
40
+ }
41
+ } else {
42
+ this
32
43
}
33
44
}
34
- def is (v : T )(block : => Unit ) { is(Seq (v))(block) }
35
- def is (v : T , vr : T * )(block : => Unit ) { is(v :: vr.toList)(block) }
45
+ def is (v : T )(block : => Unit ): SwitchContext [ T ] = is(Seq (v))(block)
46
+ def is (v : T , vr : T * )(block : => Unit ): SwitchContext [ T ] = is(v :: vr.toList)(block)
36
47
}
37
48
38
49
/** Use to specify cases in a [[switch ]] block, equivalent to a [[when$ when ]] block comparing to
39
50
* the condition variable.
40
51
*
41
52
* @note illegal outside a [[switch ]] block
42
- * @note multiple conditions may fire simultaneously
53
+ * @note must be a literal
54
+ * @note each is must be mutually exclusive
43
55
* @note dummy implementation, a macro inside [[switch ]] transforms this into the actual
44
56
* implementation
45
57
*/
@@ -80,15 +92,15 @@ object is { // scalastyle:ignore object.name
80
92
object switch { // scalastyle:ignore object.name
81
93
def apply [T <: Bits ](cond : T )(x : => Unit ): Unit = macro impl
82
94
def impl (c : Context )(cond : c.Tree )(x : c.Tree ): c.Tree = { import c .universe ._
83
- val sc = c.universe.internal.reificationSupport.freshTermName(" sc" )
84
- def extractIsStatement (tree : Tree ): List [c.universe.Tree ] = tree match {
85
- // TODO: remove when Chisel compatibility package is removed
86
- case q " Chisel.`package`.is.apply( .. $params )( .. $body ) " => List (q " $sc.is( .. $params )( .. $body ) " )
87
- case q " chisel3.util.is.apply( .. $params )( .. $body ) " => List (q " $sc.is( .. $params )( .. $body ) " )
88
- case b => throw new Exception (s " Cannot include blocks that do not begin with is() in switch. " )
89
- }
90
95
val q " .. $body" = x
91
- val ises = body.flatMap(extractIsStatement(_))
92
- q """ { val $sc = new SwitchContext( $cond); .. $ises } """
96
+ val res = body.foldLeft(q """ new SwitchContext( $cond, None, Set.empty) """ ) {
97
+ case (acc, tree) => tree match {
98
+ // TODO: remove when Chisel compatibility package is removed
99
+ case q " Chisel.`package`.is.apply( .. $params )( .. $body ) " => q " $acc.is( .. $params )( .. $body ) "
100
+ case q " chisel3.util.is.apply( .. $params )( .. $body ) " => q " $acc.is( .. $params )( .. $body ) "
101
+ case b => throw new Exception (s " Cannot include blocks that do not begin with is() in switch. " )
102
+ }
103
+ }
104
+ q """ { $res } """
93
105
}
94
106
}
0 commit comments