Skip to content

Commit 78bfa07

Browse files
committed
Merge branch 'master' into release
2 parents 34a5ed1 + 30e8eb5 commit 78bfa07

File tree

2 files changed

+63
-16
lines changed

2 files changed

+63
-16
lines changed

src/main/scala/chisel3/util/Conditional.scala

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,35 @@ object unless { // scalastyle:ignore object.name
2323
/** Implementation details for [[switch]]. See [[switch]] and [[chisel3.util.is is]] for the
2424
* user-facing API.
2525
*/
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] = {
2828
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
3134
}
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
3243
}
3344
}
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)
3647
}
3748

3849
/** Use to specify cases in a [[switch]] block, equivalent to a [[when$ when]] block comparing to
3950
* the condition variable.
4051
*
4152
* @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
4355
* @note dummy implementation, a macro inside [[switch]] transforms this into the actual
4456
* implementation
4557
*/
@@ -80,15 +92,15 @@ object is { // scalastyle:ignore object.name
8092
object switch { // scalastyle:ignore object.name
8193
def apply[T <: Bits](cond: T)(x: => Unit): Unit = macro impl
8294
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-
}
9095
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 }"""
93105
}
94106
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// See LICENSE for license details.
2+
3+
package chiselTests
4+
5+
import chisel3._
6+
import chisel3.util._
7+
import chisel3.testers.BasicTester
8+
9+
class SwitchSpec extends ChiselFlatSpec {
10+
"switch" should "require literal conditions" in {
11+
a [java.lang.IllegalArgumentException] should be thrownBy {
12+
elaborate(new Module {
13+
val io = IO(new Bundle {})
14+
val state = RegInit(0.U)
15+
val wire = WireInit(0.U)
16+
switch (state) {
17+
is (wire) { state := 1.U }
18+
}
19+
})
20+
}
21+
}
22+
it should "require mutually exclusive conditions" in {
23+
a [java.lang.IllegalArgumentException] should be thrownBy {
24+
elaborate(new Module {
25+
val io = IO(new Bundle {})
26+
val state = RegInit(0.U)
27+
switch (state) {
28+
is (0.U) { state := 1.U }
29+
is (1.U) { state := 2.U }
30+
is (0.U) { state := 3.U }
31+
}
32+
})
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)