aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala')
-rw-r--r--src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala33
1 files changed, 31 insertions, 2 deletions
diff --git a/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala b/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala
index f063f395..a7637767 100644
--- a/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala
+++ b/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala
@@ -9,6 +9,7 @@ import firrtl.transforms.ConstantPropagation
import firrtl.{bitWidth, Dshlw, Transform}
import firrtl.Mappers._
import firrtl.passes.{Pass, SplitExpressions}
+import firrtl.passes.PadWidths.forceWidth
/** Rewrites some expressions for valid/better Verilog emission.
* - solves shift right overflows by replacing the shift with 0 for UInts and MSB for SInts
@@ -47,16 +48,44 @@ object LegalizeVerilog extends Pass {
}
}
- import firrtl.passes.PadWidths.forceWidth
private def getWidth(e: Expression): Int = bitWidth(e.tpe).toInt
+ /* Verilog has the width of (a % b) = Max(W(a), W(b))
+ * FIRRTL has the width of (a % b) = Min(W(a), W(b)), which makes more sense,
+ * but nevertheless is a problem when emitting verilog
+ *
+ * This function pads the arguments to be the same [max] width (to avoid lint issues)
+ * and then performs a bit extraction back down to the correct [min] width
+ */
+ private def legalizeRem(e: Expression): Expression = e match {
+ case rem @ DoPrim(Rem, Seq(a, b), _, tpe) =>
+ val awidth = getWidth(a)
+ val bwidth = getWidth(b)
+ // Do nothing if the widths are the same
+ if (awidth == bwidth) {
+ rem
+ } else {
+ // First pad the arguments to fix lint warnings because Verilog width is max of arguments
+ val maxWidth = awidth.max(bwidth)
+ val newType = tpe.mapWidth(_ => IntWidth(maxWidth))
+ val paddedRem =
+ rem
+ .map(forceWidth(maxWidth)(_)) // Pad the input arguments
+ .mapType(_ => newType) // Also make the width for this op correct
+ // Second, bit extract back down to the min width of original arguments to match FIRRTL semantics
+ val minWidth = awidth.min(bwidth)
+ forceWidth(minWidth)(paddedRem)
+ }
+ case _ => e
+ }
+
private def onExpr(expr: Expression): Expression = expr.map(onExpr) match {
case prim: DoPrim =>
prim.op match {
case Shr => ConstantPropagation.foldShiftRight(prim)
case Bits | Head | Tail => legalizeBitExtract(prim)
case Neg => legalizeNeg(prim)
- case Rem => prim.map(forceWidth(prim.args.map(getWidth).max))
+ case Rem => legalizeRem(prim)
case Dshl =>
// special case as args aren't all same width
prim.copy(op = Dshlw, args = Seq(forceWidth(getWidth(prim))(prim.args.head), prim.args(1)))