aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchuyler Eldridge2019-10-16 12:40:08 -0400
committerSchuyler Eldridge2019-10-22 00:16:26 -0400
commit17f7bc04491397e8839a4dab8756c7fa8ac2ce13 (patch)
tree7f4148f18ece5f91d152ecaf3b2c58084fffa2b5 /src
parentb43288d588d04775230456ca85fa231a8cf397fe (diff)
Emit Verilog "else if" in register updates
Modifies the Verilog emitter to emit "else if" blocks as opposed to more deeply nested "else begin if" blocks. This improves the output Verilog readability. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/Emitter.scala58
1 files changed, 31 insertions, 27 deletions
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index d7c73e39..c427e0fc 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -534,33 +534,37 @@ class VerilogEmitter extends SeqTransform with Emitter {
}
def regUpdate(r: Expression, clk: Expression, reset: Expression, init: Expression) = {
- def addUpdate(expr: Expression, tabs: String): Seq[Seq[Any]] = {
- if (weq(expr, r)) Nil // Don't bother emitting connection of register to itself
- else expr match {
- case m: Mux =>
- if (m.tpe == ClockType) throw EmitterException("Cannot emit clock muxes directly")
- if (m.tpe == AsyncResetType) throw EmitterException("Cannot emit async reset muxes directly")
-
- def ifStatement = Seq(tabs, "if (", m.cond, ") begin")
-
- val trueCase = addUpdate(m.tval, tabs + tab)
- val elseStatement = Seq(tabs, "end else begin")
-
- def ifNotStatement = Seq(tabs, "if (!(", m.cond, ")) begin")
-
- val falseCase = addUpdate(m.fval, tabs + tab)
- val endStatement = Seq(tabs, "end")
-
- ((trueCase.nonEmpty, falseCase.nonEmpty): @unchecked) match {
- case (true, true) =>
- ifStatement +: trueCase ++: elseStatement +: falseCase :+ endStatement
- case (true, false) =>
- ifStatement +: trueCase :+ endStatement
- case (false, true) =>
- ifNotStatement +: falseCase :+ endStatement
- }
- case e => Seq(Seq(tabs, r, " <= ", e, ";"))
- }
+ def addUpdate(expr: Expression, tabs: String): Seq[Seq[Any]] = expr match {
+ case m: Mux =>
+ if (m.tpe == ClockType) throw EmitterException("Cannot emit clock muxes directly")
+ if (m.tpe == AsyncResetType) throw EmitterException("Cannot emit async reset muxes directly")
+
+ lazy val _if = Seq(tabs, "if (", m.cond, ") begin")
+ lazy val _else = Seq(tabs, "end else begin")
+ lazy val _ifNot = Seq(tabs, "if (!(", m.cond, ")) begin")
+ lazy val _end = Seq(tabs, "end")
+ lazy val _true = addUpdate(m.tval, tabs + tab)
+ lazy val _false = addUpdate(m.fval, tabs + tab)
+ lazy val _elseIfFalse = {
+ val _falsex = addUpdate(m.fval, tabs) // _false, but without an additional tab
+ Seq(tabs, "end else ", _falsex.head.tail) +: _falsex.tail
+ }
+
+ /* For a Mux assignment, there are five possibilities:
+ * 1. Both the true and false condition are self-assignments; do nothing
+ * 2. The true condition is a self-assignment; invert the false condition and use that only
+ * 3. The false condition is a self-assignment; skip the false condition
+ * 4. The false condition is a Mux; use the true condition and use 'else if' for the false condition
+ * 5. Default; use both the true and false conditions
+ */
+ (m.tval, m.fval) match {
+ case (t, f) if weq(t, r) && weq(f, r) => Nil
+ case (t, _) if weq(t, r) => _ifNot +: _false :+ _end
+ case (_, f) if weq(f, r) => _if +: _true :+ _end
+ case (_, _: Mux) => (_if +: _true) ++ _elseIfFalse
+ case _ => (_if +: _true :+ _else) ++ _false :+ _end
+ }
+ case e => Seq(Seq(tabs, r, " <= ", e, ";"))
}
if (weq(init, r)) { // Synchronous Reset
noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]()) ++= addUpdate(netlist(r), "")