diff options
| author | Schuyler Eldridge | 2019-10-16 12:40:08 -0400 |
|---|---|---|
| committer | Schuyler Eldridge | 2019-10-22 00:16:26 -0400 |
| commit | 17f7bc04491397e8839a4dab8756c7fa8ac2ce13 (patch) | |
| tree | 7f4148f18ece5f91d152ecaf3b2c58084fffa2b5 /src | |
| parent | b43288d588d04775230456ca85fa231a8cf397fe (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.scala | 58 |
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), "") |
