diff options
Diffstat (limited to 'src/main/scala/chisel3/util/Conditional.scala')
| -rw-r--r-- | src/main/scala/chisel3/util/Conditional.scala | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/util/Conditional.scala b/src/main/scala/chisel3/util/Conditional.scala new file mode 100644 index 00000000..5830e014 --- /dev/null +++ b/src/main/scala/chisel3/util/Conditional.scala @@ -0,0 +1,94 @@ +// See LICENSE for license details. + +/** Conditional blocks. + */ + +package chisel3.util + +import scala.language.reflectiveCalls +import scala.language.experimental.macros +import scala.reflect.runtime.universe._ +import scala.reflect.macros.blackbox._ + +import chisel3._ + +object unless { // scalastyle:ignore object.name + /** Does the same thing as [[when$ when]], but with the condition inverted. + */ + def apply(c: Bool)(block: => Unit) { + when (!c) { block } + } +} + +/** Implementation details for [[switch]]. See [[switch]] and [[chisel3.util.is is]] for the + * user-facing API. + */ +class SwitchContext[T <: Bits](cond: T) { + def is(v: Iterable[T])(block: => Unit) { + if (!v.isEmpty) { + when (v.map(_.asUInt === cond.asUInt).reduce(_||_)) { + block + } + } + } + def is(v: T)(block: => Unit) { is(Seq(v))(block) } + def is(v: T, vr: T*)(block: => Unit) { is(v :: vr.toList)(block) } +} + +/** Use to specify cases in a [[switch]] block, equivalent to a [[when$ when]] block comparing to + * the condition variable. + * + * @note illegal outside a [[switch]] block + * @note multiple conditions may fire simultaneously + * @note dummy implementation, a macro inside [[switch]] transforms this into the actual + * implementation + */ +object is { // scalastyle:ignore object.name + // TODO: Begin deprecation of non-type-parameterized is statements. + /** Executes `block` if the switch condition is equal to any of the values in `v`. + */ + def apply(v: Iterable[Bits])(block: => Unit) { + require(false, "The 'is' keyword may not be used outside of a switch.") + } + + /** Executes `block` if the switch condition is equal to `v`. + */ + def apply(v: Bits)(block: => Unit) { + require(false, "The 'is' keyword may not be used outside of a switch.") + } + + /** Executes `block` if the switch condition is equal to any of the values in the argument list. + */ + def apply(v: Bits, vr: Bits*)(block: => Unit) { + require(false, "The 'is' keyword may not be used outside of a switch.") + } +} + +/** Conditional logic to form a switch block. See [[is$ is]] for the case API. + * + * @example {{{ + * switch (myState) { + * is (state1) { + * // some logic here that runs when myState === state1 + * } + * is (state2) { + * // some logic here that runs when myState === state2 + * } + * } + * }}} + */ +object switch { // scalastyle:ignore object.name + def apply[T <: Bits](cond: T)(x: => Unit): Unit = macro impl + def impl(c: Context)(cond: c.Tree)(x: c.Tree): c.Tree = { import c.universe._ + val sc = c.universe.internal.reificationSupport.freshTermName("sc") + def extractIsStatement(tree: Tree): List[c.universe.Tree] = tree match { + // TODO: remove when Chisel compatibility package is removed + case q"Chisel.`package`.is.apply( ..$params )( ..$body )" => List(q"$sc.is( ..$params )( ..$body )") + case q"chisel3.util.is.apply( ..$params )( ..$body )" => List(q"$sc.is( ..$params )( ..$body )") + case b => throw new Exception(s"Cannot include blocks that do not begin with is() in switch.") + } + val q"..$body" = x + val ises = body.flatMap(extractIsStatement(_)) + q"""{ val $sc = new SwitchContext($cond); ..$ises }""" + } +} |
