diff options
Diffstat (limited to 'src/main/scala/firrtl/backends')
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))) + } +} |
