diff options
| author | Albert Magyar | 2017-08-17 17:55:44 -0700 |
|---|---|---|
| committer | Jack Koenig | 2017-08-17 17:55:44 -0700 |
| commit | 6297e00aa845cf6cc1275c05d313f3237e69de9d (patch) | |
| tree | 05363bfee404a441d5a759e292bd894c1e2db8a6 /chiselFrontend | |
| parent | 6e12ed9fd7a771eb30f44b8e1c4ab33f6ad8e0a6 (diff) | |
Use firrtl elses in elsewhen/otherwise case emission (#510)
Preprocess chisel3 IR before emission to determing whether
whens have alternatives.
Diffstat (limited to 'chiselFrontend')
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/When.scala | 55 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala | 4 |
2 files changed, 39 insertions, 20 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/When.scala b/chiselFrontend/src/main/scala/chisel3/core/When.scala index 26f939ba..55012946 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/When.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/When.scala @@ -27,35 +27,52 @@ object when { // scalastyle:ignore object.name * } * }}} */ - def apply(cond: Bool)(block: => Unit)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): WhenContext = { - new WhenContext(sourceInfo, cond, !cond, block) + + def apply(cond: => Bool)(block: => Unit)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): WhenContext = { + new WhenContext(sourceInfo, Some(() => 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. + +/** 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(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. +final class WhenContext(sourceInfo: SourceInfo, cond: Option[() => Bool], block: => Unit, firrtlDepth: Int = 0) { + + /** 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: => Unit)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): WhenContext = { - new WhenContext(sourceInfo, prevCond && elseCond, prevCond && !elseCond, block) + def elsewhen (elseCond: => Bool)(block: => Unit)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): WhenContext = { + new WhenContext(sourceInfo, Some(() => elseCond), block, firrtlDepth+1) } - /** This block of logic gets executed only if the above conditions were all - * false. No additional logic blocks may be appended past the `otherwise`. + /** 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: => Unit)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = - new WhenContext(sourceInfo, prevCond, null, block) + new WhenContext(sourceInfo, None, block, firrtlDepth+1) - pushCommand(WhenBegin(sourceInfo, cond.ref)) + /* + * + */ + if (firrtlDepth > 0) { pushCommand(AltBegin(sourceInfo)) } + cond.foreach( c => pushCommand(WhenBegin(sourceInfo, c().ref)) ) Builder.whenDepth += 1 block Builder.whenDepth -= 1 - pushCommand(WhenEnd(sourceInfo)) + cond.foreach( c => pushCommand(WhenEnd(sourceInfo,firrtlDepth)) ) + if (cond.isEmpty) { pushCommand(OtherwiseEnd(sourceInfo,firrtlDepth)) } } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala index 05cde071..b499c2b1 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -260,7 +260,9 @@ case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: Int) e case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command -case class WhenEnd(sourceInfo: SourceInfo) extends Command +case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command +case class AltBegin(sourceInfo: SourceInfo) extends Command +case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) extends Command case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command |
