aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/firrtl/backends
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/firrtl/backends')
-rw-r--r--src/main/scala/firrtl/backends/experimental/smt/FirrtlExpressionSemantics.scala4
-rw-r--r--src/main/scala/firrtl/backends/experimental/smt/FirrtlToTransitionSystem.scala6
-rw-r--r--src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala32
-rw-r--r--src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala72
4 files changed, 92 insertions, 22 deletions
diff --git a/src/main/scala/firrtl/backends/experimental/smt/FirrtlExpressionSemantics.scala b/src/main/scala/firrtl/backends/experimental/smt/FirrtlExpressionSemantics.scala
index 099b6712..2c08ff6a 100644
--- a/src/main/scala/firrtl/backends/experimental/smt/FirrtlExpressionSemantics.scala
+++ b/src/main/scala/firrtl/backends/experimental/smt/FirrtlExpressionSemantics.scala
@@ -118,8 +118,8 @@ private object FirrtlExpressionSemantics {
// the resulting value will be zero for unsigned types
// and the sign bit for signed types"
if (n >= width) {
- if (isSigned(e)) { BV1BitZero }
- else { BVSlice(toSMT(e), width - 1, width - 1) }
+ if (isSigned(e)) { BVSlice(toSMT(e), width - 1, width - 1) }
+ else { BV1BitZero }
} else {
BVSlice(toSMT(e), width - 1, n.toInt)
}
diff --git a/src/main/scala/firrtl/backends/experimental/smt/FirrtlToTransitionSystem.scala b/src/main/scala/firrtl/backends/experimental/smt/FirrtlToTransitionSystem.scala
index 78ad3c80..0b8e3ebf 100644
--- a/src/main/scala/firrtl/backends/experimental/smt/FirrtlToTransitionSystem.scala
+++ b/src/main/scala/firrtl/backends/experimental/smt/FirrtlToTransitionSystem.scala
@@ -451,7 +451,7 @@ private class ModuleScanner(
val name = loc.serialize
insertDummyAssignsForUnusedOutputs(expr)
infos.append(name -> info)
- connects.append((name, onExpression(expr, bitWidth(loc.tpe).toInt)))
+ connects.append((name, onExpression(expr, bitWidth(loc.tpe).toInt, allowNarrow = true)))
}
case i @ ir.IsInvalid(info, loc) =>
if (!isGroundType(loc.tpe)) error("All connects should have been lowered to ground type!")
@@ -591,9 +591,9 @@ private class ModuleScanner(
private case class Context() extends TranslationContext {}
- private def onExpression(e: ir.Expression, width: Int): BVExpr = {
+ private def onExpression(e: ir.Expression, width: Int, allowNarrow: Boolean = false): BVExpr = {
implicit val ctx: TranslationContext = Context()
- FirrtlExpressionSemantics.toSMT(e, width, allowNarrow = false)
+ FirrtlExpressionSemantics.toSMT(e, width, allowNarrow)
}
private def onExpression(e: ir.Expression): BVExpr = {
implicit val ctx: TranslationContext = Context()
diff --git a/src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala b/src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala
index bb385ffd..56b63d75 100644
--- a/src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala
+++ b/src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala
@@ -1,18 +1,21 @@
package firrtl
import java.io.Writer
-
import firrtl.Utils._
import firrtl.ir._
+import firrtl.stage.TransformManager.TransformDependency
import firrtl.traversals.Foreachers._
import scala.collection.mutable
-sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Emitter {
- def inputForm = form
- def outputForm = form
-
- val outputSuffix: String = form.outputSuffix
+sealed abstract class FirrtlEmitter(form: Seq[TransformDependency], val outputSuffix: String)
+ extends Transform
+ with Emitter
+ with DependencyAPIMigration {
+ override def prerequisites = form
+ override def optionalPrerequisites = Seq.empty
+ override def optionalPrerequisiteOf = Seq.empty
+ override def invalidates(a: Transform) = false
private def emitAllModules(circuit: Circuit): Seq[EmittedFirrtlModule] = {
// For a given module, returns a Seq of all modules instantited inside of it
@@ -60,14 +63,9 @@ sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Em
def emit(state: CircuitState, writer: Writer): Unit = writer.write(state.circuit.serialize)
}
-class ChirrtlEmitter extends FirrtlEmitter(CircuitForm.ChirrtlForm)
-class MinimumHighFirrtlEmitter extends FirrtlEmitter(CircuitForm.HighForm) {
- override def prerequisites = stage.Forms.MinimalHighForm
- override def optionalPrerequisites = Seq.empty
- override def optionalPrerequisiteOf = Seq.empty
- override def invalidates(a: Transform) = false
- override val outputSuffix = ".mhi.fir"
-}
-class HighFirrtlEmitter extends FirrtlEmitter(CircuitForm.HighForm)
-class MiddleFirrtlEmitter extends FirrtlEmitter(CircuitForm.MidForm)
-class LowFirrtlEmitter extends FirrtlEmitter(CircuitForm.LowForm)
+class ChirrtlEmitter extends FirrtlEmitter(stage.Forms.ChirrtlForm, ".fir")
+class MinimumHighFirrtlEmitter extends FirrtlEmitter(stage.Forms.MinimalHighForm, ".mhi.fir")
+class HighFirrtlEmitter extends FirrtlEmitter(stage.Forms.HighForm, ".hi.fir")
+class MiddleFirrtlEmitter extends FirrtlEmitter(stage.Forms.MidForm, ".mid.fir")
+class LowFirrtlEmitter extends FirrtlEmitter(stage.Forms.LowForm, ".lo.fir")
+object LowFirrtlOptimizedEmitter extends FirrtlEmitter(stage.Forms.LowFormOptimized, ".opt.lo.fir")
diff --git a/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala b/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala
new file mode 100644
index 00000000..f063f395
--- /dev/null
+++ b/src/main/scala/firrtl/backends/verilog/LegalizeVerilog.scala
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package firrtl.backends.verilog
+
+import firrtl.PrimOps._
+import firrtl.Utils.{error, getGroundZero, zero, BoolType}
+import firrtl.ir._
+import firrtl.transforms.ConstantPropagation
+import firrtl.{bitWidth, Dshlw, Transform}
+import firrtl.Mappers._
+import firrtl.passes.{Pass, SplitExpressions}
+
+/** Rewrites some expressions for valid/better Verilog emission.
+ * - solves shift right overflows by replacing the shift with 0 for UInts and MSB for SInts
+ * - ensures that bit extracts on literals get resolved
+ * - ensures that all negations are replaced with subtract from zero
+ * - adds padding for rem and dshl which breaks firrtl width invariance, but is needed to match Verilog semantics
+ */
+object LegalizeVerilog extends Pass {
+
+ override def prerequisites = firrtl.stage.Forms.LowForm
+ override def optionalPrerequisites = Seq.empty
+ override def optionalPrerequisiteOf = Seq.empty
+ override def invalidates(a: Transform): Boolean = a match {
+ case SplitExpressions => true // we generate pad and bits operations inline which need to be split up
+ case _ => false
+ }
+
+ private def legalizeBitExtract(expr: DoPrim): Expression = {
+ expr.args.head match {
+ case _: UIntLiteral | _: SIntLiteral => ConstantPropagation.constPropBitExtract(expr)
+ case _ => expr
+ }
+ }
+
+ // Convert `-x` to `0 - x`
+ private def legalizeNeg(expr: DoPrim): Expression = {
+ val arg = expr.args.head
+ arg.tpe match {
+ case tpe: SIntType =>
+ val zero = getGroundZero(tpe)
+ DoPrim(Sub, Seq(zero, arg), Nil, expr.tpe)
+ case tpe: UIntType =>
+ val zero = getGroundZero(tpe)
+ val sub = DoPrim(Sub, Seq(zero, arg), Nil, UIntType(tpe.width + IntWidth(1)))
+ DoPrim(AsSInt, Seq(sub), Nil, expr.tpe)
+ }
+ }
+
+ import firrtl.passes.PadWidths.forceWidth
+ private def getWidth(e: Expression): Int = bitWidth(e.tpe).toInt
+
+ 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 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)))
+ case _ => prim
+ }
+ case e => e // respect pre-order traversal
+ }
+
+ def run(c: Circuit): Circuit = {
+ def legalizeS(s: Statement): Statement = s.mapStmt(legalizeS).mapExpr(onExpr)
+ c.copy(modules = c.modules.map(_.map(legalizeS)))
+ }
+}