aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiuyang Liu2020-11-10 00:12:06 +0000
committerGitHub2020-11-10 00:12:06 +0000
commit92af63c599fc480f6480ee22f23763f54881085f (patch)
treeb4fde701d44a0d5a0d44d3a05489a61481762a7f
parentfe95544d573fff9bb114b3302986aa746e1f4763 (diff)
Refactor emiter (#1879)
* split big Emitter to submodules. * fix all deprecated warning. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
-rw-r--r--src/main/scala/firrtl/Compiler.scala3
-rw-r--r--src/main/scala/firrtl/Driver.scala8
-rw-r--r--src/main/scala/firrtl/Emitter.scala1455
-rw-r--r--src/main/scala/firrtl/ExecutionOptionsManager.scala24
-rw-r--r--src/main/scala/firrtl/FirrtlException.scala4
-rw-r--r--src/main/scala/firrtl/Utils.scala2
-rw-r--r--src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala67
-rw-r--r--src/main/scala/firrtl/backends/verilog/MinimumVerilogEmitter.scala13
-rw-r--r--src/main/scala/firrtl/backends/verilog/SystemVerilogEmitter.scala31
-rw-r--r--src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala1319
-rw-r--r--src/main/scala/firrtl/package.scala4
-rw-r--r--src/main/scala/firrtl/passes/InferTypes.scala4
-rw-r--r--src/main/scala/firrtl/passes/wiring/WiringUtils.scala8
-rw-r--r--src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala5
-rw-r--r--src/main/scala/firrtl/transforms/InferResets.scala4
-rw-r--r--src/main/scala/firrtl/util/BackendCompilationUtilities.scala2
-rw-r--r--src/main/scala/logger/Logger.scala6
-rw-r--r--src/main/scala/logger/LoggerOptions.scala2
18 files changed, 1493 insertions, 1468 deletions
diff --git a/src/main/scala/firrtl/Compiler.scala b/src/main/scala/firrtl/Compiler.scala
index fc852208..b4629a2a 100644
--- a/src/main/scala/firrtl/Compiler.scala
+++ b/src/main/scala/firrtl/Compiler.scala
@@ -8,7 +8,6 @@ import java.io.Writer
import scala.collection.mutable
import scala.util.Try
import scala.util.control.NonFatal
-
import firrtl.annotations._
import firrtl.ir.Circuit
import firrtl.Utils.throwInternalError
@@ -420,7 +419,7 @@ trait Emitter extends Transform {
override def invalidates(a: Transform) = false
- @deprecated("Use emission annotations instead", "firrtl 1.0")
+ @deprecated("Use emission annotations instead", "FIRRTL 1.0")
def emit(state: CircuitState, writer: Writer): Unit
/** An output suffix to use if the output of this [[Emitter]] was written to a file */
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 52ea122e..03683fda 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -34,14 +34,14 @@ import firrtl.options.phases.DeletedWrapper
* @see firrtlTests/DriverSpec.scala in the test directory for a lot more examples
* @see [[CompilerUtils.mergeTransforms]] to see how customTransformations are inserted
*/
-@deprecated("Use firrtl.stage.FirrtlStage", "1.2")
+@deprecated("Use firrtl.stage.FirrtlStage", "FIRRTL 1.2")
object Driver {
/** Print a warning message
*
* @param message error message
*/
- @deprecated("Use firrtl.options.StageUtils.dramaticWarning", "1.2")
+ @deprecated("Use firrtl.options.StageUtils.dramaticWarning", "FIRRTL 1.2")
def dramaticWarning(message: String): Unit = StageUtils.dramaticWarning(message)
/**
@@ -49,14 +49,14 @@ object Driver {
*
* @param message error message
*/
- @deprecated("Use firrtl.options.StageUtils.dramaticWarning", "1.2")
+ @deprecated("Use firrtl.options.StageUtils.dramaticWarning", "FIRRTL 1.2")
def dramaticError(message: String): Unit = StageUtils.dramaticError(message)
/** Load annotation file based on options
* @param optionsManager use optionsManager config to load annotation file if it exists
* update the firrtlOptions with new annotations if it does
*/
- @deprecated("Use side-effect free getAnnotation instead", "1.1")
+ @deprecated("Use side-effect free getAnnotation instead", "FIRRTL 1.1")
def loadAnnotations(optionsManager: ExecutionOptionsManager with HasFirrtlOptions): Unit = {
val msg = "Driver.loadAnnotations is deprecated, use Driver.getAnnotations instead"
Driver.dramaticWarning(msg)
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala
index c0be071e..7fdf0bfc 100644
--- a/src/main/scala/firrtl/Emitter.scala
+++ b/src/main/scala/firrtl/Emitter.scala
@@ -2,26 +2,14 @@
package firrtl
-import java.io.Writer
+import java.io.File
-import scala.collection.mutable
-import firrtl.ir._
-import firrtl.passes._
-import firrtl.transforms.FixAddingNegativeLiterals
-import firrtl.annotations._
-import firrtl.traversals.Foreachers._
-import firrtl.PrimOps._
-import firrtl.WrappedExpression._
-import Utils._
-import MemPortUtils.{memPortField, memType}
+import firrtl.annotations.NoTargetAnnotation
import firrtl.backends.experimental.smt.{Btor2Emitter, SMTLibEmitter}
-import firrtl.options.{CustomFileEmission, HasShellOptions, PhaseException, ShellOption}
import firrtl.options.Viewer.view
-import firrtl.stage.{FirrtlFileAnnotation, FirrtlOptions, RunFirrtlTransformAnnotation, TransformManager}
-// Datastructures
-import scala.collection.mutable.ArrayBuffer
-
-import java.io.File
+import firrtl.options.{CustomFileEmission, HasShellOptions, PhaseException, ShellOption}
+import firrtl.passes.PassException
+import firrtl.stage.{FirrtlFileAnnotation, FirrtlOptions, RunFirrtlTransformAnnotation}
case class EmitterException(message: String) extends PassException(message)
@@ -29,11 +17,12 @@ case class EmitterException(message: String) extends PassException(message)
sealed trait EmitAnnotation extends NoTargetAnnotation {
val emitter: Class[_ <: Emitter]
}
+
case class EmitCircuitAnnotation(emitter: Class[_ <: Emitter]) extends EmitAnnotation
+
case class EmitAllModulesAnnotation(emitter: Class[_ <: Emitter]) extends EmitAnnotation
object EmitCircuitAnnotation extends HasShellOptions {
-
val options = Seq(
new ShellOption[String](
longOption = "emit-circuit",
@@ -69,7 +58,6 @@ object EmitCircuitAnnotation extends HasShellOptions {
helpValueName = Some("<chirrtl|high|middle|low|verilog|mverilog|sverilog>")
)
)
-
}
object EmitAllModulesAnnotation extends HasShellOptions {
@@ -112,19 +100,19 @@ object EmitAllModulesAnnotation extends HasShellOptions {
// ***** Annotations for results of emission *****
sealed abstract class EmittedComponent {
- def name: String
- def value: String
+ def name: String
+
+ def value: String
+
def outputSuffix: String
}
+
sealed abstract class EmittedCircuit extends EmittedComponent
-final case class EmittedFirrtlCircuit(name: String, value: String, outputSuffix: String) extends EmittedCircuit
-final case class EmittedVerilogCircuit(name: String, value: String, outputSuffix: String) extends EmittedCircuit
+
sealed abstract class EmittedModule extends EmittedComponent
-final case class EmittedFirrtlModule(name: String, value: String, outputSuffix: String) extends EmittedModule
-final case class EmittedVerilogModule(name: String, value: String, outputSuffix: String) extends EmittedModule
/** Traits for Annotations containing emitted components */
-sealed trait EmittedAnnotation[T <: EmittedComponent] extends NoTargetAnnotation with CustomFileEmission {
+trait EmittedAnnotation[T <: EmittedComponent] extends NoTargetAnnotation with CustomFileEmission {
val value: T
override protected def baseFileName(annotations: AnnotationSeq): String = {
@@ -132,1425 +120,30 @@ sealed trait EmittedAnnotation[T <: EmittedComponent] extends NoTargetAnnotation
}
override protected val suffix: Option[String] = Some(value.outputSuffix)
-
}
-sealed trait EmittedCircuitAnnotation[T <: EmittedCircuit] extends EmittedAnnotation[T] {
+sealed trait EmittedCircuitAnnotation[T <: EmittedCircuit] extends EmittedAnnotation[T] {
override def getBytes = value.value.getBytes
-
}
-sealed trait EmittedModuleAnnotation[T <: EmittedModule] extends EmittedAnnotation[T] {
+sealed trait EmittedModuleAnnotation[T <: EmittedModule] extends EmittedAnnotation[T] {
override def getBytes = value.value.getBytes
-
}
+case class EmittedFirrtlModuleAnnotation(value: EmittedFirrtlModule)
+ extends EmittedModuleAnnotation[EmittedFirrtlModule]
case class EmittedFirrtlCircuitAnnotation(value: EmittedFirrtlCircuit)
extends EmittedCircuitAnnotation[EmittedFirrtlCircuit] {
override def replacements(file: File): AnnotationSeq = Seq(FirrtlFileAnnotation(file.toString))
-
}
+
+final case class EmittedFirrtlCircuit(name: String, value: String, outputSuffix: String) extends EmittedCircuit
+final case class EmittedFirrtlModule(name: String, value: String, outputSuffix: String) extends EmittedModule
+
+final case class EmittedVerilogCircuit(name: String, value: String, outputSuffix: String) extends EmittedCircuit
+final case class EmittedVerilogModule(name: String, value: String, outputSuffix: String) extends EmittedModule
case class EmittedVerilogCircuitAnnotation(value: EmittedVerilogCircuit)
extends EmittedCircuitAnnotation[EmittedVerilogCircuit]
-case class EmittedFirrtlModuleAnnotation(value: EmittedFirrtlModule)
- extends EmittedModuleAnnotation[EmittedFirrtlModule]
case class EmittedVerilogModuleAnnotation(value: EmittedVerilogModule)
extends EmittedModuleAnnotation[EmittedVerilogModule]
-
-sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Emitter {
- def inputForm = form
- def outputForm = form
-
- val outputSuffix: String = form.outputSuffix
-
- private def emitAllModules(circuit: Circuit): Seq[EmittedFirrtlModule] = {
- // For a given module, returns a Seq of all modules instantited inside of it
- def collectInstantiatedModules(mod: Module, map: Map[String, DefModule]): Seq[DefModule] = {
- // Use list instead of set to maintain order
- val modules = mutable.ArrayBuffer.empty[DefModule]
- def onStmt(stmt: Statement): Unit = stmt match {
- case DefInstance(_, _, name, _) => modules += map(name)
- case WDefInstance(_, _, name, _) => modules += map(name)
- case _: WDefInstanceConnector => throwInternalError(s"unrecognized statement: $stmt")
- case other => other.foreach(onStmt)
- }
- onStmt(mod.body)
- modules.distinct.toSeq
- }
- val modMap = circuit.modules.map(m => m.name -> m).toMap
- // Turn each module into it's own circuit with it as the top and all instantied modules as ExtModules
- circuit.modules.collect {
- case m: Module =>
- val instModules = collectInstantiatedModules(m, modMap)
- val extModules = instModules.map {
- case Module(info, name, ports, _) => ExtModule(info, name, ports, name, Seq.empty)
- case ext: ExtModule => ext
- }
- val newCircuit = Circuit(m.info, extModules :+ m, m.name)
- EmittedFirrtlModule(m.name, newCircuit.serialize, outputSuffix)
- }
- }
-
- override def execute(state: CircuitState): CircuitState = {
- val newAnnos = state.annotations.flatMap {
- case EmitCircuitAnnotation(a) if this.getClass == a =>
- Seq(
- EmittedFirrtlCircuitAnnotation(
- EmittedFirrtlCircuit(state.circuit.main, state.circuit.serialize, outputSuffix)
- )
- )
- case EmitAllModulesAnnotation(a) if this.getClass == a =>
- emitAllModules(state.circuit).map(EmittedFirrtlModuleAnnotation(_))
- case _ => Seq()
- }
- state.copy(annotations = newAnnos ++ state.annotations)
- }
-
- // Old style, deprecated
- def emit(state: CircuitState, writer: Writer): Unit = writer.write(state.circuit.serialize)
-}
-
-// ***** Start actual Emitters *****
-class ChirrtlEmitter extends FirrtlEmitter(ChirrtlForm)
-class HighFirrtlEmitter extends FirrtlEmitter(HighForm)
-class MiddleFirrtlEmitter extends FirrtlEmitter(MidForm)
-class LowFirrtlEmitter extends FirrtlEmitter(LowForm)
-
-case class VRandom(width: BigInt) extends Expression {
- def tpe = UIntType(IntWidth(width))
- def nWords = (width + 31) / 32
- def realWidth = nWords * 32
- override def serialize: String = "RANDOM"
- def mapExpr(f: Expression => Expression): Expression = this
- def mapType(f: Type => Type): Expression = this
- def mapWidth(f: Width => Width): Expression = this
- def foreachExpr(f: Expression => Unit): Unit = ()
- def foreachType(f: Type => Unit): Unit = ()
- def foreachWidth(f: Width => Unit): Unit = ()
-}
-
-object VerilogEmitter {
-
- private val unaryOps: Set[PrimOp] = Set(Andr, Orr, Xorr, Neg, Not)
-
- // To make uses more self-documenting
- private val isUnaryOp: PrimOp => Boolean = unaryOps
-
- /** Maps a [[PrimOp]] to a precedence number, lower number means higher precedence
- *
- * Only the [[PrimOp]]s contained in this map will be inlined. [[PrimOp]]s
- * like [[PrimOp.Neg]] are not in this map because inlining them may result
- * in illegal verilog like '--2sh1'
- */
- private val precedenceMap: Map[PrimOp, Int] = {
- val precedenceSeq = Seq(
- Set(Head, Tail, Bits, Shr, Pad), // Shr and Pad emit as bit select
- unaryOps,
- Set(Mul, Div, Rem),
- Set(Add, Sub, Addw, Subw),
- Set(Dshl, Dshlw, Dshr),
- Set(Lt, Leq, Gt, Geq),
- Set(Eq, Neq),
- Set(And),
- Set(Xor),
- Set(Or)
- )
- precedenceSeq.zipWithIndex.foldLeft(Map.empty[PrimOp, Int]) {
- case (map, (ops, idx)) => map ++ ops.map(_ -> idx)
- }
- }
-
- /** true if op1 has equal precendence to op2
- */
- private def precedenceEq(op1: PrimOp, op2: PrimOp): Boolean = {
- precedenceMap(op1) == precedenceMap(op2)
- }
-
- /** true if op1 has greater precendence than op2
- */
- private def precedenceGt(op1: PrimOp, op2: PrimOp): Boolean = {
- precedenceMap(op1) < precedenceMap(op2)
- }
-}
-
-class VerilogEmitter extends SeqTransform with Emitter {
- import VerilogEmitter._
-
- def inputForm = LowForm
- def outputForm = LowForm
-
- override def prerequisites = firrtl.stage.Forms.AssertsRemoved ++
- firrtl.stage.Forms.LowFormOptimized
-
- override def optionalPrerequisiteOf = Seq.empty
-
- val outputSuffix = ".v"
- val tab = " "
- def AND(e1: WrappedExpression, e2: WrappedExpression): Expression = {
- if (e1 == e2) e1.e1
- else if ((e1 == we(zero)) | (e2 == we(zero))) zero
- else if (e1 == we(one)) e2.e1
- else if (e2 == we(one)) e1.e1
- else DoPrim(And, Seq(e1.e1, e2.e1), Nil, UIntType(IntWidth(1)))
- }
- def wref(n: String, t: Type) = WRef(n, t, ExpKind, UnknownFlow)
- def remove_root(ex: Expression): Expression = ex match {
- case ex: WSubField =>
- ex.expr match {
- case (e: WSubField) => remove_root(e)
- case (_: WRef) => WRef(ex.name, ex.tpe, InstanceKind, UnknownFlow)
- }
- case _ => throwInternalError(s"shouldn't be here: remove_root($ex)")
- }
-
- /** Turn Params into Verilog Strings */
- def stringify(param: Param): String = param match {
- case IntParam(name, value) =>
- val lit =
- if (value.isValidInt) {
- s"$value"
- } else {
- val blen = value.bitLength
- if (value > 0) s"$blen'd$value" else s"-${blen + 1}'sd${value.abs}"
- }
- s".$name($lit)"
- case DoubleParam(name, value) => s".$name($value)"
- case StringParam(name, value) => s".${name}(${value.verilogEscape})"
- case RawStringParam(name, value) => s".$name($value)"
- }
- def stringify(tpe: GroundType): String = tpe match {
- case (_: UIntType | _: SIntType | _: AnalogType) =>
- val wx = bitWidth(tpe) - 1
- if (wx > 0) s"[$wx:0]" else ""
- case ClockType | AsyncResetType => ""
- case _ => throwInternalError(s"trying to write unsupported type in the Verilog Emitter: $tpe")
- }
- private def getLeadingTabs(x: Any): String = {
- x match {
- case seq: Seq[_] =>
- val head = seq.takeWhile(_ == tab).mkString
- val tail = seq.dropWhile(_ == tab).lift(0).map(getLeadingTabs).getOrElse(tab)
- head + tail
- case _ => tab
- }
- }
- def emit(x: Any)(implicit w: Writer): Unit = {
- emitCol(x, 0, getLeadingTabs(x), 0)
- }
- private def emitCast(e: Expression): Any = e.tpe match {
- case (t: UIntType) => e
- case (t: SIntType) => Seq("$signed(", e, ")")
- case ClockType => e
- case AnalogType(_) => e
- case _ => throwInternalError(s"unrecognized cast: $e")
- }
- def emit(x: Any, top: Int)(implicit w: Writer): Unit = {
- emitCol(x, top, "", 0)
- }
- private val maxCol = 120
- private def emitCol(x: Any, top: Int, tabs: String, colNum: Int)(implicit w: Writer): Int = {
- def writeCol(contents: String): Int = {
- if ((contents.size + colNum) > maxCol) {
- w.write("\n")
- w.write(tabs)
- w.write(contents)
- tabs.size + contents.size
- } else {
- w.write(contents)
- colNum + contents.size
- }
- }
-
- def cast(e: Expression): Any = e.tpe match {
- case (t: UIntType) => e
- case (t: SIntType) => Seq("$signed(", e, ")")
- case ClockType => e
- case AnalogType(_) => e
- case _ => throwInternalError(s"unrecognized cast: $e")
- }
- x match {
- case (e: DoPrim) => emitCol(op_stream(e), top + 1, tabs, colNum)
- case (e: Mux) => {
- if (e.tpe == ClockType) {
- throw EmitterException("Cannot emit clock muxes directly")
- }
- if (e.tpe == AsyncResetType) {
- throw EmitterException("Cannot emit async reset muxes directly")
- }
- emitCol(Seq(e.cond, " ? ", cast(e.tval), " : ", cast(e.fval)), top + 1, tabs, colNum)
- }
- case (e: ValidIf) => emitCol(Seq(cast(e.value)), top + 1, tabs, colNum)
- case (e: WRef) => writeCol(e.serialize)
- case (e: WSubField) => writeCol(LowerTypes.loweredName(e))
- case (e: WSubAccess) => writeCol(s"${LowerTypes.loweredName(e.expr)}[${LowerTypes.loweredName(e.index)}]")
- case (e: WSubIndex) => writeCol(e.serialize)
- case (e: Literal) => v_print(e, colNum)
- case (e: VRandom) => writeCol(s"{${e.nWords}{`RANDOM}}")
- case (t: GroundType) => writeCol(stringify(t))
- case (t: VectorType) =>
- emit(t.tpe, top + 1)
- writeCol(s"[${t.size - 1}:0]")
- case (s: String) => writeCol(s)
- case (i: Int) => writeCol(i.toString)
- case (i: Long) => writeCol(i.toString)
- case (i: BigInt) => writeCol(i.toString)
- case (i: Info) =>
- i match {
- case NoInfo => colNum // Do nothing
- case f: FileInfo =>
- val escaped = FileInfo.escapedToVerilog(f.escaped)
- w.write(s" // @[$escaped]")
- colNum
- case m: MultiInfo =>
- val escaped = FileInfo.escapedToVerilog(m.flatten.map(_.escaped).mkString(" "))
- w.write(s" // @[$escaped]")
- colNum
- }
- case (s: Seq[Any]) =>
- val nextColNum = s.foldLeft(colNum) {
- case (colNum, e) => emitCol(e, top + 1, tabs, colNum)
- }
- if (top == 0) {
- w.write("\n")
- 0
- } else {
- nextColNum
- }
- case x => throwInternalError(s"trying to emit unsupported operator: $x")
- }
- }
-
- //;------------- PASS -----------------
- def v_print(e: Expression, colNum: Int)(implicit w: Writer) = e match {
- case UIntLiteral(value, IntWidth(width)) =>
- val contents = s"$width'h${value.toString(16)}"
- w.write(contents)
- colNum + contents.size
- case SIntLiteral(value, IntWidth(width)) =>
- val stringLiteral = value.toString(16)
- val contents = stringLiteral.head match {
- case '-' if value == FixAddingNegativeLiterals.minNegValue(width) => s"$width'sh${stringLiteral.tail}"
- case '-' => s"-$width'sh${stringLiteral.tail}"
- case _ => s"$width'sh${stringLiteral}"
- }
- w.write(contents)
- colNum + contents.size
- case _ => throwInternalError(s"attempt to print unrecognized expression: $e")
- }
-
- // NOTE: We emit SInts as regular Verilog unsigned wires/regs so the real type of any SInt
- // reference is actually unsigned in the emitted Verilog. Thus we must cast refs as necessary
- // to ensure Verilog operations are signed.
- def op_stream(doprim: DoPrim): Seq[Any] = {
- def parenthesize(e: Expression, isFirst: Boolean): Any = doprim.op match {
- // these PrimOps emit either {..., a0, ...} or a0 so they never need parentheses
- case Shl | Cat | Cvt | AsUInt | AsSInt | AsClock | AsAsyncReset => e
- case _ =>
- e match {
- case e: DoPrim =>
- op_stream(e) match {
- /** DoPrims like AsUInt simply emit Seq(a0), so we need to
- * recursively check whether a0 needs to be parenthesized
- */
- case Seq(passthrough: Expression) => parenthesize(passthrough, isFirst)
-
- /* Parentheses are never needed if precedence is greater
- * Otherwise, the first expression does not need parentheses if
- * - it's precedence is equal AND
- * - the ops are not unary operations (which all have equal precedence)
- */
- case other =>
- val noParens =
- precedenceGt(e.op, doprim.op) ||
- (isFirst && precedenceEq(e.op, doprim.op) && !isUnaryOp(e.op))
- if (noParens) other else Seq("(", other, ")")
- }
-
- /** Mux args should always have parens because Mux has the lowest precedence
- */
- case _: Mux => Seq("(", e, ")")
- case _ => e
- }
- }
-
- // Cast to SInt, don't cast multiple times
- def doCast(e: Expression): Any = e match {
- case DoPrim(AsSInt, Seq(arg), _, _) => doCast(arg)
- case slit: SIntLiteral => slit
- case other => Seq("$signed(", other, ")")
- }
- def castIf(e: Expression, isFirst: Boolean = false): Any = {
- if (doprim.args.exists(_.tpe.isInstanceOf[SIntType])) {
- e.tpe match {
- case _: SIntType => doCast(e)
- case _ => throwInternalError(s"Unexpected non-SInt type for $e in $doprim")
- }
- } else {
- parenthesize(e, isFirst)
- }
- }
- def cast(e: Expression, isFirst: Boolean = false): Any = doprim.tpe match {
- case _: UIntType => parenthesize(e, isFirst)
- case _: SIntType => doCast(e)
- case _ => throwInternalError(s"Unexpected type for $e in $doprim")
- }
- def castAs(e: Expression, isFirst: Boolean = false): Any = e.tpe match {
- case _: UIntType => parenthesize(e, isFirst)
- case _: SIntType => doCast(e)
- case _ => throwInternalError(s"Unexpected type for $e in $doprim")
- }
- def a0: Expression = doprim.args.head
- def a1: Expression = doprim.args(1)
- def c0: Int = doprim.consts.head.toInt
- def c1: Int = doprim.consts(1).toInt
-
- def castCatArgs(a0: Expression, a1: Expression): Seq[Any] = {
- val a0Seq = a0 match {
- case cat @ DoPrim(PrimOps.Cat, args, _, _) => castCatArgs(args.head, args(1))
- case _ => Seq(cast(a0))
- }
- val a1Seq = a1 match {
- case cat @ DoPrim(PrimOps.Cat, args, _, _) => castCatArgs(args.head, args(1))
- case _ => Seq(cast(a1))
- }
- a0Seq ++ Seq(",") ++ a1Seq
- }
-
- doprim.op match {
- case Add => Seq(castIf(a0, true), " + ", castIf(a1))
- case Addw => Seq(castIf(a0, true), " + ", castIf(a1))
- case Sub => Seq(castIf(a0, true), " - ", castIf(a1))
- case Subw => Seq(castIf(a0, true), " - ", castIf(a1))
- case Mul => Seq(castIf(a0, true), " * ", castIf(a1))
- case Div => Seq(castIf(a0, true), " / ", castIf(a1))
- case Rem => Seq(castIf(a0, true), " % ", castIf(a1))
- case Lt => Seq(castIf(a0, true), " < ", castIf(a1))
- case Leq => Seq(castIf(a0, true), " <= ", castIf(a1))
- case Gt => Seq(castIf(a0, true), " > ", castIf(a1))
- case Geq => Seq(castIf(a0, true), " >= ", castIf(a1))
- case Eq => Seq(castIf(a0, true), " == ", castIf(a1))
- case Neq => Seq(castIf(a0, true), " != ", castIf(a1))
- case Pad =>
- val w = bitWidth(a0.tpe)
- val diff = c0 - w
- if (w == BigInt(0) || diff <= 0) Seq(a0)
- else
- doprim.tpe match {
- // Either sign extend or zero extend.
- // If width == BigInt(1), don't extract bit
- case (_: SIntType) if w == BigInt(1) => Seq("{", c0, "{", a0, "}}")
- case (_: SIntType) => Seq("{{", diff, "{", parenthesize(a0, true), "[", w - 1, "]}},", a0, "}")
- case (_) => Seq("{{", diff, "'d0}, ", a0, "}")
- }
- // Because we don't support complex Expressions, all casts are ignored
- // This simplifies handling of assignment of a signed expression to an unsigned LHS value
- // which does not require a cast in Verilog
- case AsUInt | AsSInt | AsClock | AsAsyncReset => Seq(a0)
- case Dshlw => Seq(cast(a0), " << ", parenthesize(a1, false))
- case Dshl => Seq(cast(a0), " << ", parenthesize(a1, false))
- case Dshr =>
- doprim.tpe match {
- case (_: SIntType) => Seq(cast(a0), " >>> ", parenthesize(a1, false))
- case (_) => Seq(cast(a0), " >> ", parenthesize(a1, false))
- }
- case Shl => if (c0 > 0) Seq("{", cast(a0), s", $c0'h0}") else Seq(cast(a0))
- case Shr if c0 >= bitWidth(a0.tpe) =>
- error("Verilog emitter does not support SHIFT_RIGHT >= arg width")
- case Shr if c0 == (bitWidth(a0.tpe) - 1) => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - 1, "]")
- case Shr => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - 1, ":", c0, "]")
- case Neg => Seq("-", cast(a0, true))
- case Cvt =>
- a0.tpe match {
- case (_: UIntType) => Seq("{1'b0,", cast(a0), "}")
- case (_: SIntType) => Seq(cast(a0))
- }
- case Not => Seq("~", parenthesize(a0, true))
- case And => Seq(castAs(a0, true), " & ", castAs(a1))
- case Or => Seq(castAs(a0, true), " | ", castAs(a1))
- case Xor => Seq(castAs(a0, true), " ^ ", castAs(a1))
- case Andr => Seq("&", cast(a0, true))
- case Orr => Seq("|", cast(a0, true))
- case Xorr => Seq("^", cast(a0, true))
- case Cat => "{" +: (castCatArgs(a0, a1) :+ "}")
- // If selecting zeroth bit and single-bit wire, just emit the wire
- case Bits if c0 == 0 && c1 == 0 && bitWidth(a0.tpe) == BigInt(1) => Seq(a0)
- case Bits if c0 == c1 => Seq(parenthesize(a0, true), "[", c0, "]")
- case Bits => Seq(parenthesize(a0, true), "[", c0, ":", c1, "]")
- // If selecting zeroth bit and single-bit wire, just emit the wire
- case Head if c0 == 1 && bitWidth(a0.tpe) == BigInt(1) => Seq(a0)
- case Head if c0 == 1 => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - 1, "]")
- case Head =>
- val msb = bitWidth(a0.tpe) - 1
- val lsb = bitWidth(a0.tpe) - c0
- Seq(parenthesize(a0, true), "[", msb, ":", lsb, "]")
- case Tail if c0 == (bitWidth(a0.tpe) - 1) => Seq(parenthesize(a0, true), "[0]")
- case Tail => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - c0 - 1, ":0]")
- }
- }
-
- /**
- * Gets a reference to a verilog renderer. This is used by the current standard verilog emission process
- * but allows access to individual portions, in particular, this function can be used to generate
- * the header for a verilog file without generating anything else.
- *
- * @param m the start module
- * @param moduleMap a way of finding other modules
- * @param writer where rendering will be placed
- * @return the render reference
- */
- def getRenderer(m: Module, moduleMap: Map[String, DefModule])(implicit writer: Writer): VerilogRender = {
- new VerilogRender(m, moduleMap)(writer)
- }
-
- /**
- * Gets a reference to a verilog renderer. This is used by the current standard verilog emission process
- * but allows access to individual portions, in particular, this function can be used to generate
- * the header for a verilog file without generating anything else.
- *
- * @param descriptions comments to be emitted
- * @param m the start module
- * @param moduleMap a way of finding other modules
- * @param writer where rendering will be placed
- * @return the render reference
- */
- def getRenderer(
- descriptions: Seq[DescriptionAnnotation],
- m: Module,
- moduleMap: Map[String, DefModule]
- )(
- implicit writer: Writer
- ): VerilogRender = {
- val newMod = new AddDescriptionNodes().executeModule(m, descriptions)
-
- newMod match {
- case DescribedMod(d, pds, m: Module) =>
- new VerilogRender(d, pds, m, moduleMap, "", new EmissionOptions(Seq.empty))(writer)
- case m: Module => new VerilogRender(m, moduleMap)(writer)
- }
- }
-
- def addFormalStatement(
- formals: mutable.Map[Expression, ArrayBuffer[Seq[Any]]],
- clk: Expression,
- en: Expression,
- stmt: Seq[Any],
- info: Info,
- msg: StringLit
- ): Unit = {
- throw EmitterException(
- "Cannot emit verification statements in Verilog" +
- "(2001). Use the SystemVerilog emitter instead."
- )
- }
-
- /**
- * Store Emission option per Target
- * Guarantee only one emission option per Target
- */
- private[firrtl] class EmissionOptionMap[V <: EmissionOption](val df: V) {
- private val m = collection.mutable.HashMap[ReferenceTarget, V]().withDefaultValue(df)
- def +=(elem: (ReferenceTarget, V)): EmissionOptionMap.this.type = {
- if (m.contains(elem._1))
- throw EmitterException(s"Multiple EmissionOption for the target ${elem._1} (${m(elem._1)} ; ${elem._2})")
- m += (elem)
- this
- }
- def apply(key: ReferenceTarget): V = m.apply(key)
- }
-
- /** Provide API to retrieve EmissionOptions based on the provided [[AnnotationSeq]]
- *
- * @param annotations : AnnotationSeq to be searched for EmissionOptions
- */
- private[firrtl] class EmissionOptions(annotations: AnnotationSeq) {
- // Private so that we can present an immutable API
- private val memoryEmissionOption = new EmissionOptionMap[MemoryEmissionOption](MemoryEmissionOptionDefault)
- private val registerEmissionOption = new EmissionOptionMap[RegisterEmissionOption](RegisterEmissionOptionDefault)
- private val wireEmissionOption = new EmissionOptionMap[WireEmissionOption](WireEmissionOptionDefault)
- private val portEmissionOption = new EmissionOptionMap[PortEmissionOption](PortEmissionOptionDefault)
- private val nodeEmissionOption = new EmissionOptionMap[NodeEmissionOption](NodeEmissionOptionDefault)
- private val connectEmissionOption = new EmissionOptionMap[ConnectEmissionOption](ConnectEmissionOptionDefault)
-
- def getMemoryEmissionOption(target: ReferenceTarget): MemoryEmissionOption =
- memoryEmissionOption(target)
-
- def getRegisterEmissionOption(target: ReferenceTarget): RegisterEmissionOption =
- registerEmissionOption(target)
-
- def getWireEmissionOption(target: ReferenceTarget): WireEmissionOption =
- wireEmissionOption(target)
-
- def getPortEmissionOption(target: ReferenceTarget): PortEmissionOption =
- portEmissionOption(target)
-
- def getNodeEmissionOption(target: ReferenceTarget): NodeEmissionOption =
- nodeEmissionOption(target)
-
- def getConnectEmissionOption(target: ReferenceTarget): ConnectEmissionOption =
- connectEmissionOption(target)
-
- private val emissionAnnos = annotations.collect {
- case m: SingleTargetAnnotation[ReferenceTarget] @unchecked with EmissionOption => m
- }
- // using multiple foreach instead of a single partial function as an Annotation can gather multiple EmissionOptions for simplicity
- emissionAnnos.foreach {
- case a: MemoryEmissionOption => memoryEmissionOption += ((a.target, a))
- case _ =>
- }
- emissionAnnos.foreach {
- case a: RegisterEmissionOption => registerEmissionOption += ((a.target, a))
- case _ =>
- }
- emissionAnnos.foreach {
- case a: WireEmissionOption => wireEmissionOption += ((a.target, a))
- case _ =>
- }
- emissionAnnos.foreach {
- case a: PortEmissionOption => portEmissionOption += ((a.target, a))
- case _ =>
- }
- emissionAnnos.foreach {
- case a: NodeEmissionOption => nodeEmissionOption += ((a.target, a))
- case _ =>
- }
- emissionAnnos.foreach {
- case a: ConnectEmissionOption => connectEmissionOption += ((a.target, a))
- case _ =>
- }
- }
-
- /**
- * Used by getRenderer, it has machinery to produce verilog from IR.
- * Making this a class allows access to particular parts of the verilog emission.
- *
- * @param description a description of the start module
- * @param portDescriptions a map of port name to description
- * @param m the start module
- * @param moduleMap a map of modules so submodules can be discovered
- * @param writer where rendered information is placed.
- */
- class VerilogRender(
- description: Seq[Description],
- portDescriptions: Map[String, Seq[Description]],
- m: Module,
- moduleMap: Map[String, DefModule],
- circuitName: String,
- emissionOptions: EmissionOptions
- )(
- implicit writer: Writer) {
-
- def this(
- m: Module,
- moduleMap: Map[String, DefModule],
- circuitName: String,
- emissionOptions: EmissionOptions
- )(
- implicit writer: Writer
- ) = {
- this(Seq(), Map.empty, m, moduleMap, circuitName, emissionOptions)(writer)
- }
- def this(m: Module, moduleMap: Map[String, DefModule])(implicit writer: Writer) = {
- this(Seq(), Map.empty, m, moduleMap, "", new EmissionOptions(Seq.empty))(writer)
- }
-
- val netlist = mutable.LinkedHashMap[WrappedExpression, InfoExpr]()
- val namespace = Namespace(m)
- namespace.newName("_RAND") // Start rand names at _RAND_0
- def build_netlist(s: Statement): Unit = {
- s.foreach(build_netlist)
- s match {
- case sx: Connect => netlist(sx.loc) = InfoExpr(sx.info, sx.expr)
- case sx: IsInvalid => error("Should have removed these!")
- // TODO Since only register update and memories use the netlist anymore, I think nodes are
- // unnecessary
- case sx: DefNode =>
- val e = WRef(sx.name, sx.value.tpe, NodeKind, SourceFlow)
- netlist(e) = InfoExpr(sx.info, sx.value)
- case _ =>
- }
- }
-
- val portdefs = ArrayBuffer[Seq[Any]]()
- // maps ifdef guard to declaration blocks
- val ifdefDeclares: mutable.Map[String, ArrayBuffer[Seq[Any]]] = mutable.Map().withDefault { key =>
- val value = ArrayBuffer[Seq[Any]]()
- ifdefDeclares(key) = value
- value
- }
- val declares = ArrayBuffer[Seq[Any]]()
- val instdeclares = ArrayBuffer[Seq[Any]]()
- val assigns = ArrayBuffer[Seq[Any]]()
- val attachSynAssigns = ArrayBuffer.empty[Seq[Any]]
- val attachAliases = ArrayBuffer.empty[Seq[Any]]
- // No (aka synchronous) always blocks, keyed by clock
- val noResetAlwaysBlocks = mutable.LinkedHashMap[Expression, ArrayBuffer[Seq[Any]]]()
- // One always block per async reset register, (Clock, Reset, Content)
- // An alternative approach is to have one always block per combination of clock and async reset,
- // but Formality doesn't allow more than 1 statement inside async reset always blocks
- val asyncResetAlwaysBlocks = mutable.ArrayBuffer[(Expression, Expression, Seq[Any])]()
- // Used to determine type of initvar for initializing memories
- var maxMemSize: BigInt = BigInt(0)
- // maps ifdef guard to initial blocks
- val ifdefInitials: mutable.Map[String, ArrayBuffer[Seq[Any]]] = mutable.Map().withDefault { key =>
- val value = ArrayBuffer[Seq[Any]]()
- ifdefInitials(key) = value
- value
- }
- val initials = ArrayBuffer[Seq[Any]]()
- // In Verilog, async reset registers are expressed using always blocks of the form:
- // always @(posedge clock or posedge reset) begin
- // if (reset) ...
- // There is a fundamental mismatch between this representation which treats async reset
- // registers as edge-triggered when in reality they are level-triggered.
- // When not randomized, there is no mismatch because the async reset transition at the start
- // of simulation from X to 1 triggers the posedge block for async reset.
- // When randomized, this can result in silicon-simulation mismatch when async reset is held high
- // upon power on with no clock, then async reset is dropped before the clock starts. In this
- // circumstance, the async reset register will be randomized in simulation instead of being
- // reset. To fix this, we need extra initial block logic to reset async reset registers again
- // post-randomize.
- val asyncInitials = ArrayBuffer[Seq[Any]]()
- // memories need to be initialized even when randomization is disabled
- val memoryInitials = ArrayBuffer[Seq[Any]]()
- val simulates = ArrayBuffer[Seq[Any]]()
- val formals = mutable.LinkedHashMap[Expression, ArrayBuffer[Seq[Any]]]()
-
- def bigIntToVLit(bi: BigInt): String =
- if (bi.isValidInt) bi.toString else s"${bi.bitLength}'d$bi"
-
- // declare vector type with no preset and optionally with an ifdef guard
- private def declareVectorType(
- b: String,
- n: String,
- tpe: Type,
- size: BigInt,
- info: Info,
- ifdefOpt: Option[String]
- ): Unit = {
- val decl = Seq(b, " ", tpe, " ", n, " [0:", bigIntToVLit(size - 1), "];", info)
- if (ifdefOpt.isDefined) {
- ifdefDeclares(ifdefOpt.get) += decl
- } else {
- declares += decl
- }
- }
-
- // original vector type declare without initial value
- def declareVectorType(b: String, n: String, tpe: Type, size: BigInt, info: Info): Unit =
- declareVectorType(b, n, tpe, size, info, None)
-
- // declare vector type with initial value
- def declareVectorType(b: String, n: String, tpe: Type, size: BigInt, info: Info, preset: Expression): Unit = {
- declares += Seq(b, " ", tpe, " ", n, " [0:", bigIntToVLit(size - 1), "] = ", preset, ";", info)
- }
-
- val moduleTarget = CircuitTarget(circuitName).module(m.name)
-
- // declare with initial value
- def declare(b: String, n: String, t: Type, info: Info, preset: Expression) = t match {
- case tx: VectorType =>
- declareVectorType(b, n, tx.tpe, tx.size, info, preset)
- case tx =>
- declares += Seq(b, " ", tx, " ", n, " = ", preset, ";", info)
- }
-
- // original declare without initial value and optinally with an ifdef guard
- private def declare(b: String, n: String, t: Type, info: Info, ifdefOpt: Option[String]): Unit = t match {
- case tx: VectorType =>
- declareVectorType(b, n, tx.tpe, tx.size, info, ifdefOpt)
- case tx =>
- val decl = Seq(b, " ", tx, " ", n, ";", info)
- if (ifdefOpt.isDefined) {
- ifdefDeclares(ifdefOpt.get) += decl
- } else {
- declares += decl
- }
- }
-
- // original declare without initial value and with an ifdef guard
- private def declare(b: String, n: String, t: Type, info: Info, ifdef: String): Unit =
- declare(b, n, t, info, Some(ifdef))
-
- // original declare without initial value
- def declare(b: String, n: String, t: Type, info: Info): Unit =
- declare(b, n, t, info, None)
-
- def assign(e: Expression, infoExpr: InfoExpr): Unit =
- assign(e, infoExpr.expr, infoExpr.info)
-
- def assign(e: Expression, value: Expression, info: Info): Unit = {
- assigns += Seq("assign ", e, " = ", value, ";", info)
- }
-
- // In simulation, assign garbage under a predicate
- def garbageAssign(e: Expression, syn: Expression, garbageCond: Expression, info: Info) = {
- assigns += Seq("`ifndef RANDOMIZE_GARBAGE_ASSIGN")
- assigns += Seq("assign ", e, " = ", syn, ";", info)
- assigns += Seq("`else")
- assigns += Seq(
- "assign ",
- e,
- " = ",
- garbageCond,
- " ? ",
- rand_string(syn.tpe, "RANDOMIZE_GARBAGE_ASSIGN"),
- " : ",
- syn,
- ";",
- info
- )
- assigns += Seq("`endif // RANDOMIZE_GARBAGE_ASSIGN")
- }
-
- def invalidAssign(e: Expression) = {
- assigns += Seq("`ifdef RANDOMIZE_INVALID_ASSIGN")
- assigns += Seq("assign ", e, " = ", rand_string(e.tpe, "RANDOMIZE_INVALID_ASSIGN"), ";")
- assigns += Seq("`endif // RANDOMIZE_INVALID_ASSIGN")
- }
-
- def regUpdate(r: Expression, clk: Expression, reset: Expression, init: Expression) = {
- def addUpdate(info: Info, expr: Expression, tabs: Seq[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")
-
- val (eninfo, tinfo, finfo) = MultiInfo.demux(info)
- lazy val _if = Seq(tabs, "if (", m.cond, ") begin", eninfo)
- lazy val _else = Seq(tabs, "end else begin")
- lazy val _ifNot = Seq(tabs, "if (!(", m.cond, ")) begin", eninfo)
- lazy val _end = Seq(tabs, "end")
- lazy val _true = addUpdate(tinfo, m.tval, tab +: tabs)
- lazy val _false = addUpdate(finfo, m.fval, tab +: tabs)
- lazy val _elseIfFalse = {
- val _falsex = addUpdate(finfo, 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, with one subcase for asynchronous reset:
- * 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
- * a) The reset is asynchronous; emit both 'if' and a trivial 'else' to avoid latches
- * b) The reset is synchronous; 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) =>
- m.cond.tpe match {
- case AsyncResetType => (_if +: _true :+ _else) ++ _true :+ _end
- case _ => _if +: _true :+ _end
- }
- case (_, _: Mux) => (_if +: _true) ++ _elseIfFalse
- case _ => (_if +: _true :+ _else) ++ _false :+ _end
- }
- case e => Seq(Seq(tabs, r, " <= ", e, ";", info))
- }
- if (weq(init, r)) { // Synchronous Reset
- val InfoExpr(info, e) = netlist(r)
- noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]()) ++= addUpdate(info, e, Seq.empty)
- } else { // Asynchronous Reset
- assert(reset.tpe == AsyncResetType, "Error! Synchronous reset should have been removed!")
- val tv = init
- val InfoExpr(finfo, fv) = netlist(r)
- // TODO add register info argument and build a MultiInfo to pass
- asyncResetAlwaysBlocks += (
- (
- clk,
- reset,
- addUpdate(NoInfo, Mux(reset, tv, fv, mux_type_and_widths(tv, fv)), Seq.empty)
- )
- )
- }
- }
-
- def update(e: Expression, value: Expression, clk: Expression, en: Expression, info: Info) = {
- val lines = noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
- if (weq(en, one)) lines += Seq(e, " <= ", value, ";")
- else {
- lines += Seq("if(", en, ") begin")
- lines += Seq(tab, e, " <= ", value, ";", info)
- lines += Seq("end")
- }
- }
-
- // Declares an intermediate wire to hold a large enough random number.
- // Then, return the correct number of bits selected from the random value
- def rand_string(t: Type, ifdefOpt: Option[String]): Seq[Any] = {
- val nx = namespace.newName("_RAND")
- val rand = VRandom(bitWidth(t))
- val tx = SIntType(IntWidth(rand.realWidth))
- declare("reg", nx, tx, NoInfo, ifdefOpt)
- val initial = Seq(wref(nx, tx), " = ", VRandom(bitWidth(t)), ";")
- if (ifdefOpt.isDefined) {
- ifdefInitials(ifdefOpt.get) += initial
- } else {
- initials += initial
- }
- Seq(nx, "[", bitWidth(t) - 1, ":0]")
- }
-
- def rand_string(t: Type, ifdef: String): Seq[Any] = rand_string(t, Some(ifdef))
-
- def rand_string(t: Type): Seq[Any] = rand_string(t, None)
-
- def initialize(e: Expression, reset: Expression, init: Expression) = {
- val randString = rand_string(e.tpe, "RANDOMIZE_REG_INIT")
- ifdefInitials("RANDOMIZE_REG_INIT") += Seq(e, " = ", randString, ";")
- reset.tpe match {
- case AsyncResetType =>
- asyncInitials += Seq("if (", reset, ") begin")
- asyncInitials += Seq(tab, e, " = ", init, ";")
- asyncInitials += Seq("end")
- case _ => // do nothing
- }
- }
-
- def initialize_mem(s: DefMemory, opt: MemoryEmissionOption): Unit = {
- if (s.depth > maxMemSize) {
- maxMemSize = s.depth
- }
-
- val dataWidth = bitWidth(s.dataType)
- val maxDataValue = (BigInt(1) << dataWidth.toInt) - 1
-
- def checkValueRange(value: BigInt, at: String): Unit = {
- if (value < 0) throw EmitterException(s"Memory ${at} cannot be initialized with negative value: $value")
- if (value > maxDataValue)
- throw EmitterException(s"Memory ${at} cannot be initialized with value: $value. Too large (> $maxDataValue)!")
- }
-
- opt.initValue match {
- case MemoryArrayInit(values) =>
- if (values.length != s.depth)
- throw EmitterException(
- s"Memory ${s.name} of depth ${s.depth} cannot be initialized with an array of length ${values.length}!"
- )
- val memName = LowerTypes.loweredName(wref(s.name, s.dataType))
- values.zipWithIndex.foreach {
- case (value, addr) =>
- checkValueRange(value, s"${s.name}[$addr]")
- val access = s"$memName[${bigIntToVLit(addr)}]"
- memoryInitials += Seq(access, " = ", bigIntToVLit(value), ";")
- }
- case MemoryScalarInit(value) =>
- checkValueRange(value, s.name)
- // note: s.dataType is the incorrect type for initvar, but it is ignored in the serialization
- val index = wref("initvar", s.dataType)
- memoryInitials += Seq("for (initvar = 0; initvar < ", bigIntToVLit(s.depth), "; initvar = initvar+1)")
- memoryInitials += Seq(
- tab,
- WSubAccess(wref(s.name, s.dataType), index, s.dataType, SinkFlow),
- " = ",
- bigIntToVLit(value),
- ";"
- )
- case MemoryRandomInit =>
- // note: s.dataType is the incorrect type for initvar, but it is ignored in the serialization
- val index = wref("initvar", s.dataType)
- val rstring = rand_string(s.dataType, "RANDOMIZE_MEM_INIT")
- ifdefInitials("RANDOMIZE_MEM_INIT") += Seq(
- "for (initvar = 0; initvar < ",
- bigIntToVLit(s.depth),
- "; initvar = initvar+1)"
- )
- ifdefInitials("RANDOMIZE_MEM_INIT") += Seq(
- tab,
- WSubAccess(wref(s.name, s.dataType), index, s.dataType, SinkFlow),
- " = ",
- rstring,
- ";"
- )
- }
- }
-
- def simulate(clk: Expression, en: Expression, s: Seq[Any], cond: Option[String], info: Info) = {
- val lines = noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
- lines += Seq("`ifndef SYNTHESIS")
- if (cond.nonEmpty) {
- lines += Seq(s"`ifdef ${cond.get}")
- lines += Seq(tab, s"if (`${cond.get}) begin")
- lines += Seq("`endif")
- }
- lines += Seq(tab, tab, "if (", en, ") begin")
- lines += Seq(tab, tab, tab, s, info)
- lines += Seq(tab, tab, "end")
- if (cond.nonEmpty) {
- lines += Seq(s"`ifdef ${cond.get}")
- lines += Seq(tab, "end")
- lines += Seq("`endif")
- }
- lines += Seq("`endif // SYNTHESIS")
- }
-
- def addFormal(clk: Expression, en: Expression, stmt: Seq[Any], info: Info, msg: StringLit): Unit = {
- addFormalStatement(formals, clk, en, stmt, info, msg)
- }
-
- def formalStatement(op: Formal.Value, cond: Expression): Seq[Any] = {
- Seq(op.toString, "(", cond, ");")
- }
-
- def stop(ret: Int): Seq[Any] = Seq(if (ret == 0) "$finish;" else "$fatal;")
-
- def printf(str: StringLit, args: Seq[Expression]): Seq[Any] = {
- val strx = str.verilogEscape +: args.flatMap(Seq(",", _))
- Seq("$fwrite(32'h80000002,", strx, ");")
- }
-
- // turn strings into Seq[String] verilog comments
- def build_comment(desc: String): Seq[Seq[String]] = {
- val lines = desc.split("\n").toSeq
-
- if (lines.size > 1) {
- val lineSeqs = lines.tail.map {
- case "" => Seq(" *")
- case nonEmpty => Seq(" * ", nonEmpty)
- }
- Seq("/* ", lines.head) +: lineSeqs :+ Seq(" */")
- } else {
- Seq(Seq("// ", lines(0)))
- }
- }
-
- def build_attribute(attrs: String): Seq[Seq[String]] = {
- Seq(Seq("(* ") ++ Seq(attrs) ++ Seq(" *)"))
- }
-
- // Turn ports into Seq[String] and add to portdefs
- def build_ports(): Unit = {
- def padToMax(strs: Seq[String]): Seq[String] = {
- val len = if (strs.nonEmpty) strs.map(_.length).max else 0
- strs.map(_.padTo(len, ' '))
- }
-
- // Turn directions into strings (and AnalogType into inout)
- val dirs = m.ports.map {
- case Port(_, name, dir, tpe) =>
- (dir, tpe) match {
- case (_, AnalogType(_)) => "inout " // padded to length of output
- case (Input, _) => "input "
- case (Output, _) => "output"
- }
- }
- // Turn types into strings, all ports must be GroundTypes
- val tpes = m.ports.map {
- case Port(_, _, _, tpe: GroundType) => stringify(tpe)
- case port: Port => error(s"Trying to emit non-GroundType Port $port")
- }
-
- // dirs are already padded
- (dirs, padToMax(tpes), m.ports).zipped.toSeq.zipWithIndex.foreach {
- case ((dir, tpe, Port(info, name, _, _)), i) =>
- portDescriptions.get(name).map {
- case d =>
- portdefs += Seq("")
- portdefs ++= build_description(d)
- }
-
- if (i != m.ports.size - 1) {
- portdefs += Seq(dir, " ", tpe, " ", name, ",", info)
- } else {
- portdefs += Seq(dir, " ", tpe, " ", name, info)
- }
- }
- }
-
- def build_description(d: Seq[Description]): Seq[Seq[String]] = d.flatMap {
- case DocString(desc) => build_comment(desc.string)
- case Attribute(attr) => build_attribute(attr.string)
- }
-
- def build_streams(s: Statement): Unit = {
- val withoutDescription = s match {
- case DescribedStmt(d, stmt) =>
- stmt match {
- case sx: IsDeclaration =>
- declares ++= build_description(d)
- case _ =>
- }
- stmt
- case stmt => stmt
- }
- withoutDescription.foreach(build_streams)
- withoutDescription match {
- case sx @ Connect(info, loc @ WRef(_, _, PortKind | WireKind | InstanceKind, _), expr) =>
- assign(loc, expr, info)
- case sx: DefWire =>
- declare("wire", sx.name, sx.tpe, sx.info)
- case sx: DefRegister =>
- val options = emissionOptions.getRegisterEmissionOption(moduleTarget.ref(sx.name))
- val e = wref(sx.name, sx.tpe)
- if (options.useInitAsPreset) {
- declare("reg", sx.name, sx.tpe, sx.info, sx.init)
- regUpdate(e, sx.clock, sx.reset, e)
- } else {
- declare("reg", sx.name, sx.tpe, sx.info)
- regUpdate(e, sx.clock, sx.reset, sx.init)
- }
- if (!options.disableRandomization)
- initialize(e, sx.reset, sx.init)
- case sx: DefNode =>
- declare("wire", sx.name, sx.value.tpe, sx.info, sx.value)
- case sx: Stop =>
- simulate(sx.clk, sx.en, stop(sx.ret), Some("STOP_COND"), sx.info)
- case sx: Print =>
- simulate(sx.clk, sx.en, printf(sx.string, sx.args), Some("PRINTF_COND"), sx.info)
- case sx: Verification =>
- addFormal(sx.clk, sx.en, formalStatement(sx.op, sx.pred), sx.info, sx.msg)
- // If we are emitting an Attach, it must not have been removable in VerilogPrep
- case sx: Attach =>
- // For Synthesis
- // Note that this is quadratic in the number of things attached
- for (set <- sx.exprs.toSet.subsets(2)) {
- val (a, b) = set.toSeq match {
- case Seq(x, y) => (x, y)
- }
- // Synthesizable ones as well
- attachSynAssigns += Seq("assign ", a, " = ", b, ";", sx.info)
- attachSynAssigns += Seq("assign ", b, " = ", a, ";", sx.info)
- }
- // alias implementation for everything else
- attachAliases += Seq("alias ", sx.exprs.flatMap(e => Seq(e, " = ")).init, ";", sx.info)
- case sx: WDefInstanceConnector =>
- val (module, params) = moduleMap(sx.module) match {
- case DescribedMod(_, _, ExtModule(_, _, _, extname, params)) => (extname, params)
- case DescribedMod(_, _, Module(_, name, _, _)) => (name, Seq.empty)
- case ExtModule(_, _, _, extname, params) => (extname, params)
- case Module(_, name, _, _) => (name, Seq.empty)
- }
- val ps = if (params.nonEmpty) params.map(stringify).mkString("#(", ", ", ") ") else ""
- instdeclares += Seq(module, " ", ps, sx.name, " (", sx.info)
- for (((port, ref), i) <- sx.portCons.zipWithIndex) {
- val line = Seq(tab, ".", remove_root(port), "(", ref, ")")
- if (i != sx.portCons.size - 1) instdeclares += Seq(line, ",")
- else instdeclares += line
- }
- instdeclares += Seq(");")
- case sx: DefMemory =>
- val options = emissionOptions.getMemoryEmissionOption(moduleTarget.ref(sx.name))
- val fullSize = sx.depth * (sx.dataType match {
- case GroundType(IntWidth(width)) => width
- })
- val decl = if (fullSize > (1 << 29)) "reg /* sparse */" else "reg"
- declareVectorType(decl, sx.name, sx.dataType, sx.depth, sx.info)
- initialize_mem(sx, options)
- if (sx.readLatency != 0 || sx.writeLatency != 1)
- throw EmitterException(
- "All memories should be transformed into " +
- "blackboxes or combinational by previous passses"
- )
- for (r <- sx.readers) {
- val data = memPortField(sx, r, "data")
- val addr = memPortField(sx, r, "addr")
- // Ports should share an always@posedge, so can't have intermediary wire
-
- declare("wire", LowerTypes.loweredName(data), data.tpe, sx.info)
- declare("wire", LowerTypes.loweredName(addr), addr.tpe, sx.info)
- // declare("wire", LowerTypes.loweredName(en), en.tpe)
-
- //; Read port
- assign(addr, netlist(addr))
- // assign(en, netlist(en)) //;Connects value to m.r.en
- val mem = WRef(sx.name, memType(sx), MemKind, UnknownFlow)
- val memPort = WSubAccess(mem, addr, sx.dataType, UnknownFlow)
- val depthValue = UIntLiteral(sx.depth, IntWidth(sx.depth.bitLength))
- val garbageGuard = DoPrim(Geq, Seq(addr, depthValue), Seq(), UnknownType)
-
- if ((sx.depth & (sx.depth - 1)) == 0)
- assign(data, memPort, sx.info)
- else
- garbageAssign(data, memPort, garbageGuard, sx.info)
- }
-
- for (w <- sx.writers) {
- val data = memPortField(sx, w, "data")
- val addr = memPortField(sx, w, "addr")
- val mask = memPortField(sx, w, "mask")
- val en = memPortField(sx, w, "en")
- //Ports should share an always@posedge, so can't have intermediary wire
- // TODO should we use the info here for anything?
- val InfoExpr(_, clk) = netlist(memPortField(sx, w, "clk"))
-
- declare("wire", LowerTypes.loweredName(data), data.tpe, sx.info)
- declare("wire", LowerTypes.loweredName(addr), addr.tpe, sx.info)
- declare("wire", LowerTypes.loweredName(mask), mask.tpe, sx.info)
- declare("wire", LowerTypes.loweredName(en), en.tpe, sx.info)
-
- // Write port
- assign(data, netlist(data))
- assign(addr, netlist(addr))
- assign(mask, netlist(mask))
- assign(en, netlist(en))
-
- val mem = WRef(sx.name, memType(sx), MemKind, UnknownFlow)
- val memPort = WSubAccess(mem, addr, sx.dataType, UnknownFlow)
- update(memPort, data, clk, AND(en, mask), sx.info)
- }
-
- if (sx.readwriters.nonEmpty)
- throw EmitterException(
- "All readwrite ports should be transformed into " +
- "read & write ports by previous passes"
- )
- case _ =>
- }
- }
-
- def emit_streams(): Unit = {
- build_description(description).foreach(emit(_))
- emit(Seq("module ", m.name, "(", m.info))
- for (x <- portdefs) emit(Seq(tab, x))
- emit(Seq(");"))
-
- ifdefDeclares.toSeq.sortWith(_._1 < _._1).foreach {
- case (ifdef, declares) =>
- emit(Seq("`ifdef " + ifdef))
- for (x <- declares) emit(Seq(tab, x))
- emit(Seq("`endif // " + ifdef))
- }
- for (x <- declares) emit(Seq(tab, x))
- for (x <- instdeclares) emit(Seq(tab, x))
- for (x <- assigns) emit(Seq(tab, x))
- if (attachAliases.nonEmpty) {
- emit(Seq("`ifdef SYNTHESIS"))
- for (x <- attachSynAssigns) emit(Seq(tab, x))
- emit(Seq("`elsif verilator"))
- emit(
- Seq(
- tab,
- "`error \"Verilator does not support alias and thus cannot arbirarily connect bidirectional wires and ports\""
- )
- )
- emit(Seq("`else"))
- for (x <- attachAliases) emit(Seq(tab, x))
- emit(Seq("`endif"))
- }
-
- for ((clk, content) <- noResetAlwaysBlocks if content.nonEmpty) {
- emit(Seq(tab, "always @(posedge ", clk, ") begin"))
- for (line <- content) emit(Seq(tab, tab, line))
- emit(Seq(tab, "end"))
- }
-
- for ((clk, reset, content) <- asyncResetAlwaysBlocks if content.nonEmpty) {
- emit(Seq(tab, "always @(posedge ", clk, " or posedge ", reset, ") begin"))
- for (line <- content) emit(Seq(tab, tab, line))
- emit(Seq(tab, "end"))
- }
-
- if (initials.nonEmpty || ifdefInitials.nonEmpty || memoryInitials.nonEmpty) {
- emit(Seq("// Register and memory initialization"))
- emit(Seq("`ifdef RANDOMIZE_GARBAGE_ASSIGN"))
- emit(Seq("`define RANDOMIZE"))
- emit(Seq("`endif"))
- emit(Seq("`ifdef RANDOMIZE_INVALID_ASSIGN"))
- emit(Seq("`define RANDOMIZE"))
- emit(Seq("`endif"))
- emit(Seq("`ifdef RANDOMIZE_REG_INIT"))
- emit(Seq("`define RANDOMIZE"))
- emit(Seq("`endif"))
- emit(Seq("`ifdef RANDOMIZE_MEM_INIT"))
- emit(Seq("`define RANDOMIZE"))
- emit(Seq("`endif"))
- emit(Seq("`ifndef RANDOM"))
- emit(Seq("`define RANDOM $random"))
- emit(Seq("`endif"))
- // the initvar is also used to initialize memories to constants
- if (memoryInitials.isEmpty) emit(Seq("`ifdef RANDOMIZE_MEM_INIT"))
- // Since simulators don't actually support memories larger than 2^31 - 1, there is no reason
- // to change Verilog emission in the common case. Instead, we only emit a larger initvar
- // where necessary
- if (maxMemSize.isValidInt) {
- emit(Seq(" integer initvar;"))
- } else {
- // Width must be able to represent maxMemSize because that's the upper bound in init loop
- val width = maxMemSize.bitLength - 1 // minus one because [width-1:0] has a width of "width"
- emit(Seq(s" reg [$width:0] initvar;"))
- }
- if (memoryInitials.isEmpty) emit(Seq("`endif"))
- emit(Seq("`ifndef SYNTHESIS"))
- // User-defined macro of code to run before an initial block
- emit(Seq("`ifdef FIRRTL_BEFORE_INITIAL"))
- emit(Seq("`FIRRTL_BEFORE_INITIAL"))
- emit(Seq("`endif"))
- emit(Seq("initial begin"))
- emit(Seq(" `ifdef RANDOMIZE"))
- emit(Seq(" `ifdef INIT_RANDOM"))
- emit(Seq(" `INIT_RANDOM"))
- emit(Seq(" `endif"))
- // This enables testbenches to seed the random values at some time
- // before `RANDOMIZE_DELAY (or the legacy value 0.002 if
- // `RANDOMIZE_DELAY is not defined).
- // Verilator does not support delay statements, so they are omitted.
- emit(Seq(" `ifndef VERILATOR"))
- emit(Seq(" `ifdef RANDOMIZE_DELAY"))
- emit(Seq(" #`RANDOMIZE_DELAY begin end"))
- emit(Seq(" `else"))
- emit(Seq(" #0.002 begin end"))
- emit(Seq(" `endif"))
- emit(Seq(" `endif"))
- ifdefInitials.toSeq.sortWith(_._1 < _._1).foreach {
- case (ifdef, initials) =>
- emit(Seq("`ifdef " + ifdef))
- for (x <- initials) emit(Seq(tab, x))
- emit(Seq("`endif // " + ifdef))
- }
- for (x <- initials) emit(Seq(tab, x))
- for (x <- asyncInitials) emit(Seq(tab, x))
- emit(Seq(" `endif // RANDOMIZE"))
- for (x <- memoryInitials) emit(Seq(tab, x))
- emit(Seq("end // initial"))
- // User-defined macro of code to run after an initial block
- emit(Seq("`ifdef FIRRTL_AFTER_INITIAL"))
- emit(Seq("`FIRRTL_AFTER_INITIAL"))
- emit(Seq("`endif"))
- emit(Seq("`endif // SYNTHESIS"))
- }
-
- if (formals.keys.nonEmpty) {
- for ((clk, content) <- formals if content.nonEmpty) {
- emit(Seq(tab, "always @(posedge ", clk, ") begin"))
- for (line <- content) emit(Seq(tab, tab, line))
- emit(Seq(tab, "end"))
- }
- }
-
- emit(Seq("endmodule"))
- }
-
- /**
- * The standard verilog emitter, wraps up everything into the
- * verilog
- * @return
- */
- def emit_verilog(): DefModule = {
-
- build_netlist(m.body)
- build_ports()
- build_streams(m.body)
- emit_streams()
- m
- }
-
- /**
- * This emits a verilog module that can be bound to a module defined in chisel.
- * It uses the same machinery as the general emitter in order to insure that
- * parameters signature is exactly the same as the module being bound to
- * @param overrideName Override the module name
- * @param body the body of the bind module
- * @return A module constructed from the body
- */
- def emitVerilogBind(overrideName: String, body: String): DefModule = {
- build_netlist(m.body)
- build_ports()
-
- build_description(description).foreach(emit(_))
-
- emit(Seq("module ", overrideName, "(", m.info))
- for (x <- portdefs) emit(Seq(tab, x))
-
- emit(Seq(");"))
- emit(body)
- emit(Seq("endmodule"), top = 0)
- m
- }
- }
-
- /** Preamble for every emitted Verilog file */
- def transforms = new TransformManager(firrtl.stage.Forms.VerilogOptimized, prerequisites).flattenedTransformOrder
-
- def emit(state: CircuitState, writer: Writer): Unit = {
- val cs = runTransforms(state)
- val emissionOptions = new EmissionOptions(cs.annotations)
- val moduleMap = cs.circuit.modules.map(m => m.name -> m).toMap
- cs.circuit.modules.foreach {
- case dm @ DescribedMod(d, pds, m: Module) =>
- val renderer = new VerilogRender(d, pds, m, moduleMap, cs.circuit.main, emissionOptions)(writer)
- renderer.emit_verilog()
- case m: Module =>
- val renderer = new VerilogRender(m, moduleMap, cs.circuit.main, emissionOptions)(writer)
- renderer.emit_verilog()
- case _ => // do nothing
- }
- }
-
- override def execute(state: CircuitState): CircuitState = {
- val writerToString =
- (writer: java.io.StringWriter) => writer.toString.replaceAll("""(?m) +$""", "") // trim trailing whitespace
-
- val newAnnos = state.annotations.flatMap {
- case EmitCircuitAnnotation(a) if this.getClass == a =>
- val writer = new java.io.StringWriter
- emit(state, writer)
- Seq(
- EmittedVerilogCircuitAnnotation(
- EmittedVerilogCircuit(state.circuit.main, writerToString(writer), outputSuffix)
- )
- )
-
- case EmitAllModulesAnnotation(a) if this.getClass == a =>
- val cs = runTransforms(state)
- val emissionOptions = new EmissionOptions(cs.annotations)
- val moduleMap = cs.circuit.modules.map(m => m.name -> m).toMap
-
- cs.circuit.modules.flatMap {
- case dm @ DescribedMod(d, pds, module: Module) =>
- val writer = new java.io.StringWriter
- val renderer = new VerilogRender(d, pds, module, moduleMap, cs.circuit.main, emissionOptions)(writer)
- renderer.emit_verilog()
- Some(
- EmittedVerilogModuleAnnotation(EmittedVerilogModule(module.name, writerToString(writer), outputSuffix))
- )
- case module: Module =>
- val writer = new java.io.StringWriter
- val renderer = new VerilogRender(module, moduleMap, cs.circuit.main, emissionOptions)(writer)
- renderer.emit_verilog()
- Some(
- EmittedVerilogModuleAnnotation(EmittedVerilogModule(module.name, writerToString(writer), outputSuffix))
- )
- case _ => None
- }
- case _ => Seq()
- }
- state.copy(annotations = newAnnos ++ state.annotations)
- }
-}
-
-class MinimumVerilogEmitter extends VerilogEmitter with Emitter {
-
- override def prerequisites = firrtl.stage.Forms.AssertsRemoved ++
- firrtl.stage.Forms.LowFormMinimumOptimized
-
- override def transforms =
- new TransformManager(firrtl.stage.Forms.VerilogMinimumOptimized, prerequisites).flattenedTransformOrder
-
-}
-
-class SystemVerilogEmitter extends VerilogEmitter {
- override val outputSuffix: String = ".sv"
-
- override def prerequisites = firrtl.stage.Forms.LowFormOptimized
-
- override def addFormalStatement(
- formals: mutable.Map[Expression, ArrayBuffer[Seq[Any]]],
- clk: Expression,
- en: Expression,
- stmt: Seq[Any],
- info: Info,
- msg: StringLit
- ): Unit = {
- val lines = formals.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
- lines += Seq("// ", msg.serialize)
- lines += Seq("if (", en, ") begin")
- lines += Seq(tab, stmt, info)
- lines += Seq("end")
- }
-
- override def execute(state: CircuitState): CircuitState = {
- super.execute(state)
- }
-}
diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala
index 8602b984..b8c0dedd 100644
--- a/src/main/scala/firrtl/ExecutionOptionsManager.scala
+++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala
@@ -32,10 +32,10 @@ import scala.collection.Seq
* '''NOTE''' In all derived trait/classes, if you intend on maintaining backwards compatibility,
* be sure to add new options at the end of the current ones and don't remove any existing ones.
*/
-@deprecated("Use firrtl.options.HasScoptOptions and/or library/transform registration", "1.2")
+@deprecated("Use firrtl.options.HasScoptOptions and/or library/transform registration", "FIRRTL 1.2")
trait ComposableOptions
-@deprecated("Use firrtl.options.{ExecutionOptionsManager, TerminateOnExit, DuplicateHandling}", "1.2")
+@deprecated("Use firrtl.options.{ExecutionOptionsManager, TerminateOnExit, DuplicateHandling}", "FIRRTL 1.2")
abstract class HasParser(applicationName: String) {
final val parser = new OptionParser[Unit](applicationName) {
var terminateOnExit = true
@@ -66,7 +66,7 @@ abstract class HasParser(applicationName: String) {
* For example, in chisel, by deferring this it is possible for the execute there to first elaborate the
* circuit and then set the topName from that if it has not already been set.
*/
-@deprecated("Use a FirrtlOptionsView, LoggerOptionsView, or construct your own view of an AnnotationSeq", "1.2")
+@deprecated("Use a FirrtlOptionsView, LoggerOptionsView, or construct your own view of an AnnotationSeq", "FIRRTL 1.2")
case class CommonOptions(
topName: String = "",
targetDirName: String = ".",
@@ -96,7 +96,7 @@ case class CommonOptions(
programArgs.map(a => ProgramArgsAnnotation(a))
}
-@deprecated("Specify command line arguments in an Annotation mixing in HasScoptOptions", "1.2")
+@deprecated("Specify command line arguments in an Annotation mixing in HasScoptOptions", "FIRRTL 1.2")
trait HasCommonOptions {
self: ExecutionOptionsManager =>
var commonOptions = CommonOptions()
@@ -210,7 +210,7 @@ final case class OneFilePerModule(targetDir: String) extends OutputConfig
* @param compilerName which compiler to use
* @param annotations annotations to pass to compiler
*/
-@deprecated("Use a FirrtlOptionsView or construct your own view of an AnnotationSeq", "1.2")
+@deprecated("Use a FirrtlOptionsView or construct your own view of an AnnotationSeq", "FIRRTL 1.2")
case class FirrtlExecutionOptions(
inputFileNameOverride: String = "",
outputFileNameOverride: String = "",
@@ -330,7 +330,7 @@ case class FirrtlExecutionOptions(
* @param optionsManager this is needed to access build function and its common options
* @return
*/
- @deprecated("Use FirrtlOptions.annotationFileNames instead", "1.1")
+ @deprecated("Use FirrtlOptions.annotationFileNames instead", "FIRRTL 1.1")
def getAnnotationFileName(optionsManager: ExecutionOptionsManager): String = {
optionsManager.getBuildFileName("anno", annotationFileNameOverride)
}
@@ -363,7 +363,7 @@ case class FirrtlExecutionOptions(
}
}
-@deprecated("Specify command line arguments in an Annotation mixing in HasScoptOptions", "1.2")
+@deprecated("Specify command line arguments in an Annotation mixing in HasScoptOptions", "FIRRTL 1.2")
trait HasFirrtlOptions {
self: ExecutionOptionsManager =>
var firrtlOptions = FirrtlExecutionOptions()
@@ -589,10 +589,10 @@ trait HasFirrtlOptions {
parser.note("")
}
-@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "1.2")
+@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "FIRRTL 1.2")
sealed trait FirrtlExecutionResult
-@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "1.2")
+@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "FIRRTL 1.2")
object FirrtlExecutionSuccess {
def apply(
emitType: String,
@@ -613,7 +613,7 @@ object FirrtlExecutionSuccess {
* "sverilog"
* @param emitted The emitted result of compilation
*/
-@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "1.2")
+@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "FIRRTL 1.2")
class FirrtlExecutionSuccess(
val emitType: String,
val emitted: String,
@@ -625,13 +625,13 @@ class FirrtlExecutionSuccess(
*
* @param message Some kind of hint as to what went wrong.
*/
-@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "1.2")
+@deprecated("Use FirrtlStage and examine the output AnnotationSeq directly", "FIRRTL 1.2")
case class FirrtlExecutionFailure(message: String) extends FirrtlExecutionResult
/**
* @param applicationName The name shown in the usage
*/
-@deprecated("Use new FirrtlStage infrastructure", "1.2")
+@deprecated("Use new FirrtlStage infrastructure", "FIRRTL 1.2")
class ExecutionOptionsManager(val applicationName: String) extends HasParser(applicationName) with HasCommonOptions {
def parse(args: Array[String]): Boolean = {
diff --git a/src/main/scala/firrtl/FirrtlException.scala b/src/main/scala/firrtl/FirrtlException.scala
index 91d5350e..685718cd 100644
--- a/src/main/scala/firrtl/FirrtlException.scala
+++ b/src/main/scala/firrtl/FirrtlException.scala
@@ -4,7 +4,7 @@ package firrtl
import scala.util.control.NoStackTrace
-@deprecated("External users should use either FirrtlUserException or their own hierarchy", "1.2")
+@deprecated("External users should use either FirrtlUserException or their own hierarchy", "FIRRTL 1.2")
object FIRRTLException {
def defaultMessage(message: String, cause: Throwable) = {
if (message != null) {
@@ -16,7 +16,7 @@ object FIRRTLException {
}
}
}
-@deprecated("External users should use either FirrtlUserException or their own hierarchy", "1.2")
+@deprecated("External users should use either FirrtlUserException or their own hierarchy", "FIRRTL 1.2")
class FIRRTLException(val str: String, cause: Throwable = null)
extends RuntimeException(FIRRTLException.defaultMessage(str, cause), cause)
diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala
index ac987456..a52e451f 100644
--- a/src/main/scala/firrtl/Utils.scala
+++ b/src/main/scala/firrtl/Utils.scala
@@ -307,7 +307,7 @@ object Utils extends LazyLogging {
onExp(expression)
ReferenceTarget(main, module, Nil, ref, tokens.toSeq)
}
- @deprecated("get_flip is fundamentally slow, use to_flip(flow(expr))", "1.2")
+ @deprecated("get_flip is fundamentally slow, use to_flip(flow(expr))", "FIRRTL 1.2")
def get_flip(t: Type, i: Int, f: Orientation): Orientation = {
if (i >= get_size(t)) throwInternalError(s"get_flip: shouldn't be here - $i >= get_size($t)")
t match {
diff --git a/src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala b/src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala
new file mode 100644
index 00000000..26e03633
--- /dev/null
+++ b/src/main/scala/firrtl/backends/firrtl/FirrtlEmitter.scala
@@ -0,0 +1,67 @@
+package firrtl
+
+import java.io.Writer
+
+import firrtl.Utils._
+import firrtl.ir._
+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
+
+ private def emitAllModules(circuit: Circuit): Seq[EmittedFirrtlModule] = {
+ // For a given module, returns a Seq of all modules instantited inside of it
+ def collectInstantiatedModules(mod: Module, map: Map[String, DefModule]): Seq[DefModule] = {
+ // Use list instead of set to maintain order
+ val modules = mutable.ArrayBuffer.empty[DefModule]
+ def onStmt(stmt: Statement): Unit = stmt match {
+ case DefInstance(_, _, name, _) => modules += map(name)
+ case WDefInstance(_, _, name, _) => modules += map(name)
+ case _: WDefInstanceConnector => throwInternalError(s"unrecognized statement: $stmt")
+ case other => other.foreach(onStmt)
+ }
+ onStmt(mod.body)
+ modules.distinct.toSeq
+ }
+ val modMap = circuit.modules.map(m => m.name -> m).toMap
+ // Turn each module into it's own circuit with it as the top and all instantied modules as ExtModules
+ circuit.modules.collect {
+ case m: Module =>
+ val instModules = collectInstantiatedModules(m, modMap)
+ val extModules = instModules.map {
+ case Module(info, name, ports, _) => ExtModule(info, name, ports, name, Seq.empty)
+ case ext: ExtModule => ext
+ }
+ val newCircuit = Circuit(m.info, extModules :+ m, m.name)
+ EmittedFirrtlModule(m.name, newCircuit.serialize, outputSuffix)
+ }
+ }
+
+ override def execute(state: CircuitState): CircuitState = {
+ val newAnnos = state.annotations.flatMap {
+ case EmitCircuitAnnotation(a) if this.getClass == a =>
+ Seq(
+ EmittedFirrtlCircuitAnnotation(
+ EmittedFirrtlCircuit(state.circuit.main, state.circuit.serialize, outputSuffix)
+ )
+ )
+ case EmitAllModulesAnnotation(a) if this.getClass == a =>
+ emitAllModules(state.circuit).map(EmittedFirrtlModuleAnnotation(_))
+ case _ => Seq()
+ }
+ state.copy(annotations = newAnnos ++ state.annotations)
+ }
+
+ // Old style, deprecated
+ def emit(state: CircuitState, writer: Writer): Unit = writer.write(state.circuit.serialize)
+}
+
+class ChirrtlEmitter extends FirrtlEmitter(ChirrtlForm)
+class HighFirrtlEmitter extends FirrtlEmitter(HighForm)
+class MiddleFirrtlEmitter extends FirrtlEmitter(MidForm)
+class LowFirrtlEmitter extends FirrtlEmitter(LowForm)
diff --git a/src/main/scala/firrtl/backends/verilog/MinimumVerilogEmitter.scala b/src/main/scala/firrtl/backends/verilog/MinimumVerilogEmitter.scala
new file mode 100644
index 00000000..4d8bade6
--- /dev/null
+++ b/src/main/scala/firrtl/backends/verilog/MinimumVerilogEmitter.scala
@@ -0,0 +1,13 @@
+package firrtl
+
+import firrtl.stage.TransformManager
+
+class MinimumVerilogEmitter extends VerilogEmitter with Emitter {
+
+ override def prerequisites = firrtl.stage.Forms.AssertsRemoved ++
+ firrtl.stage.Forms.LowFormMinimumOptimized
+
+ override def transforms =
+ new TransformManager(firrtl.stage.Forms.VerilogMinimumOptimized, prerequisites).flattenedTransformOrder
+
+}
diff --git a/src/main/scala/firrtl/backends/verilog/SystemVerilogEmitter.scala b/src/main/scala/firrtl/backends/verilog/SystemVerilogEmitter.scala
new file mode 100644
index 00000000..2d8e3089
--- /dev/null
+++ b/src/main/scala/firrtl/backends/verilog/SystemVerilogEmitter.scala
@@ -0,0 +1,31 @@
+package firrtl
+
+import firrtl.ir.{Expression, Info, StringLit}
+
+import scala.collection.mutable
+import scala.collection.mutable.ArrayBuffer
+
+class SystemVerilogEmitter extends VerilogEmitter {
+ override val outputSuffix: String = ".sv"
+
+ override def prerequisites = firrtl.stage.Forms.LowFormOptimized
+
+ override def addFormalStatement(
+ formals: mutable.Map[Expression, ArrayBuffer[Seq[Any]]],
+ clk: Expression,
+ en: Expression,
+ stmt: Seq[Any],
+ info: Info,
+ msg: StringLit
+ ): Unit = {
+ val lines = formals.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
+ lines += Seq("// ", msg.serialize)
+ lines += Seq("if (", en, ") begin")
+ lines += Seq(tab, stmt, info)
+ lines += Seq("end")
+ }
+
+ override def execute(state: CircuitState): CircuitState = {
+ super.execute(state)
+ }
+}
diff --git a/src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala b/src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala
new file mode 100644
index 00000000..3ecd1279
--- /dev/null
+++ b/src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala
@@ -0,0 +1,1319 @@
+package firrtl
+
+import java.io.Writer
+
+import firrtl.ir._
+import firrtl.PrimOps._
+import firrtl.Utils._
+import firrtl.WrappedExpression._
+import firrtl.traversals.Foreachers._
+import firrtl.annotations.{CircuitTarget, ReferenceTarget, SingleTargetAnnotation}
+import firrtl.passes.LowerTypes
+import firrtl.passes.MemPortUtils._
+import firrtl.stage.TransformManager
+import firrtl.transforms.FixAddingNegativeLiterals
+
+import scala.collection.mutable
+import scala.collection.mutable.ArrayBuffer
+
+object VerilogEmitter {
+ private val unaryOps: Set[PrimOp] = Set(Andr, Orr, Xorr, Neg, Not)
+
+ // To make uses more self-documenting
+ private val isUnaryOp: PrimOp => Boolean = unaryOps
+
+ /** Maps a [[PrimOp]] to a precedence number, lower number means higher precedence
+ *
+ * Only the [[PrimOp]]s contained in this map will be inlined. [[PrimOp]]s
+ * like [[Neg]] are not in this map because inlining them may result
+ * in illegal verilog like '--2sh1'
+ */
+ private val precedenceMap: Map[PrimOp, Int] = {
+ val precedenceSeq = Seq(
+ Set(Head, Tail, Bits, Shr, Pad), // Shr and Pad emit as bit select
+ unaryOps,
+ Set(Mul, Div, Rem),
+ Set(Add, Sub, Addw, Subw),
+ Set(Dshl, Dshlw, Dshr),
+ Set(Lt, Leq, Gt, Geq),
+ Set(Eq, Neq),
+ Set(And),
+ Set(Xor),
+ Set(Or)
+ )
+ precedenceSeq.zipWithIndex.foldLeft(Map.empty[PrimOp, Int]) {
+ case (map, (ops, idx)) => map ++ ops.map(_ -> idx)
+ }
+ }
+
+ /** true if op1 has equal precendence to op2
+ */
+ private def precedenceEq(op1: PrimOp, op2: PrimOp): Boolean = {
+ precedenceMap(op1) == precedenceMap(op2)
+ }
+
+ /** true if op1 has greater precendence than op2
+ */
+ private def precedenceGt(op1: PrimOp, op2: PrimOp): Boolean = {
+ precedenceMap(op1) < precedenceMap(op2)
+ }
+}
+
+class VerilogEmitter extends SeqTransform with Emitter {
+ import VerilogEmitter._
+
+ def inputForm = LowForm
+ def outputForm = LowForm
+
+ override def prerequisites = firrtl.stage.Forms.AssertsRemoved ++
+ firrtl.stage.Forms.LowFormOptimized
+
+ override def optionalPrerequisiteOf = Seq.empty
+
+ val outputSuffix = ".v"
+ val tab = " "
+ def AND(e1: WrappedExpression, e2: WrappedExpression): Expression = {
+ if (e1 == e2) e1.e1
+ else if ((e1 == we(zero)) | (e2 == we(zero))) zero
+ else if (e1 == we(one)) e2.e1
+ else if (e2 == we(one)) e1.e1
+ else DoPrim(And, Seq(e1.e1, e2.e1), Nil, UIntType(IntWidth(1)))
+ }
+ def wref(n: String, t: Type) = WRef(n, t, ExpKind, UnknownFlow)
+ def remove_root(ex: Expression): Expression = ex match {
+ case ex: WSubField =>
+ ex.expr match {
+ case (e: WSubField) => remove_root(e)
+ case (_: WRef) => WRef(ex.name, ex.tpe, InstanceKind, UnknownFlow)
+ }
+ case _ => throwInternalError(s"shouldn't be here: remove_root($ex)")
+ }
+
+ /** Turn Params into Verilog Strings */
+ def stringify(param: Param): String = param match {
+ case IntParam(name, value) =>
+ val lit =
+ if (value.isValidInt) {
+ s"$value"
+ } else {
+ val blen = value.bitLength
+ if (value > 0) s"$blen'd$value" else s"-${blen + 1}'sd${value.abs}"
+ }
+ s".$name($lit)"
+ case DoubleParam(name, value) => s".$name($value)"
+ case StringParam(name, value) => s".${name}(${value.verilogEscape})"
+ case RawStringParam(name, value) => s".$name($value)"
+ }
+ def stringify(tpe: GroundType): String = tpe match {
+ case (_: UIntType | _: SIntType | _: AnalogType) =>
+ val wx = bitWidth(tpe) - 1
+ if (wx > 0) s"[$wx:0]" else ""
+ case ClockType | AsyncResetType => ""
+ case _ => throwInternalError(s"trying to write unsupported type in the Verilog Emitter: $tpe")
+ }
+ private def getLeadingTabs(x: Any): String = {
+ x match {
+ case seq: Seq[_] =>
+ val head = seq.takeWhile(_ == tab).mkString
+ val tail = seq.dropWhile(_ == tab).lift(0).map(getLeadingTabs).getOrElse(tab)
+ head + tail
+ case _ => tab
+ }
+ }
+ def emit(x: Any)(implicit w: Writer): Unit = {
+ emitCol(x, 0, getLeadingTabs(x), 0)
+ }
+ private def emitCast(e: Expression): Any = e.tpe match {
+ case (t: UIntType) => e
+ case (t: SIntType) => Seq("$signed(", e, ")")
+ case ClockType => e
+ case AnalogType(_) => e
+ case _ => throwInternalError(s"unrecognized cast: $e")
+ }
+ def emit(x: Any, top: Int)(implicit w: Writer): Unit = {
+ emitCol(x, top, "", 0)
+ }
+ private val maxCol = 120
+ private def emitCol(x: Any, top: Int, tabs: String, colNum: Int)(implicit w: Writer): Int = {
+ def writeCol(contents: String): Int = {
+ if ((contents.size + colNum) > maxCol) {
+ w.write("\n")
+ w.write(tabs)
+ w.write(contents)
+ tabs.size + contents.size
+ } else {
+ w.write(contents)
+ colNum + contents.size
+ }
+ }
+
+ def cast(e: Expression): Any = e.tpe match {
+ case (t: UIntType) => e
+ case (t: SIntType) => Seq("$signed(", e, ")")
+ case ClockType => e
+ case AnalogType(_) => e
+ case _ => throwInternalError(s"unrecognized cast: $e")
+ }
+ x match {
+ case (e: DoPrim) => emitCol(op_stream(e), top + 1, tabs, colNum)
+ case (e: Mux) => {
+ if (e.tpe == ClockType) {
+ throw EmitterException("Cannot emit clock muxes directly")
+ }
+ if (e.tpe == AsyncResetType) {
+ throw EmitterException("Cannot emit async reset muxes directly")
+ }
+ emitCol(Seq(e.cond, " ? ", cast(e.tval), " : ", cast(e.fval)), top + 1, tabs, colNum)
+ }
+ case (e: ValidIf) => emitCol(Seq(cast(e.value)), top + 1, tabs, colNum)
+ case (e: WRef) => writeCol(e.serialize)
+ case (e: WSubField) => writeCol(LowerTypes.loweredName(e))
+ case (e: WSubAccess) => writeCol(s"${LowerTypes.loweredName(e.expr)}[${LowerTypes.loweredName(e.index)}]")
+ case (e: WSubIndex) => writeCol(e.serialize)
+ case (e: Literal) => v_print(e, colNum)
+ case (e: VRandom) => writeCol(s"{${e.nWords}{`RANDOM}}")
+ case (t: GroundType) => writeCol(stringify(t))
+ case (t: VectorType) =>
+ emit(t.tpe, top + 1)
+ writeCol(s"[${t.size - 1}:0]")
+ case (s: String) => writeCol(s)
+ case (i: Int) => writeCol(i.toString)
+ case (i: Long) => writeCol(i.toString)
+ case (i: BigInt) => writeCol(i.toString)
+ case (i: Info) =>
+ i match {
+ case NoInfo => colNum // Do nothing
+ case f: FileInfo =>
+ val escaped = FileInfo.escapedToVerilog(f.escaped)
+ w.write(s" // @[$escaped]")
+ colNum
+ case m: MultiInfo =>
+ val escaped = FileInfo.escapedToVerilog(m.flatten.map(_.escaped).mkString(" "))
+ w.write(s" // @[$escaped]")
+ colNum
+ }
+ case (s: Seq[Any]) =>
+ val nextColNum = s.foldLeft(colNum) {
+ case (colNum, e) => emitCol(e, top + 1, tabs, colNum)
+ }
+ if (top == 0) {
+ w.write("\n")
+ 0
+ } else {
+ nextColNum
+ }
+ case x => throwInternalError(s"trying to emit unsupported operator: $x")
+ }
+ }
+
+ //;------------- PASS -----------------
+ def v_print(e: Expression, colNum: Int)(implicit w: Writer) = e match {
+ case UIntLiteral(value, IntWidth(width)) =>
+ val contents = s"$width'h${value.toString(16)}"
+ w.write(contents)
+ colNum + contents.size
+ case SIntLiteral(value, IntWidth(width)) =>
+ val stringLiteral = value.toString(16)
+ val contents = stringLiteral.head match {
+ case '-' if value == FixAddingNegativeLiterals.minNegValue(width) => s"$width'sh${stringLiteral.tail}"
+ case '-' => s"-$width'sh${stringLiteral.tail}"
+ case _ => s"$width'sh${stringLiteral}"
+ }
+ w.write(contents)
+ colNum + contents.size
+ case _ => throwInternalError(s"attempt to print unrecognized expression: $e")
+ }
+
+ // NOTE: We emit SInts as regular Verilog unsigned wires/regs so the real type of any SInt
+ // reference is actually unsigned in the emitted Verilog. Thus we must cast refs as necessary
+ // to ensure Verilog operations are signed.
+ def op_stream(doprim: DoPrim): Seq[Any] = {
+ def parenthesize(e: Expression, isFirst: Boolean): Any = doprim.op match {
+ // these PrimOps emit either {..., a0, ...} or a0 so they never need parentheses
+ case Shl | Cat | Cvt | AsUInt | AsSInt | AsClock | AsAsyncReset => e
+ case _ =>
+ e match {
+ case e: DoPrim =>
+ op_stream(e) match {
+ /** DoPrims like AsUInt simply emit Seq(a0), so we need to
+ * recursively check whether a0 needs to be parenthesized
+ */
+ case Seq(passthrough: Expression) => parenthesize(passthrough, isFirst)
+
+ /* Parentheses are never needed if precedence is greater
+ * Otherwise, the first expression does not need parentheses if
+ * - it's precedence is equal AND
+ * - the ops are not unary operations (which all have equal precedence)
+ */
+ case other =>
+ val noParens =
+ precedenceGt(e.op, doprim.op) ||
+ (isFirst && precedenceEq(e.op, doprim.op) && !isUnaryOp(e.op))
+ if (noParens) other else Seq("(", other, ")")
+ }
+
+ /** Mux args should always have parens because Mux has the lowest precedence
+ */
+ case _: Mux => Seq("(", e, ")")
+ case _ => e
+ }
+ }
+
+ // Cast to SInt, don't cast multiple times
+ def doCast(e: Expression): Any = e match {
+ case DoPrim(AsSInt, Seq(arg), _, _) => doCast(arg)
+ case slit: SIntLiteral => slit
+ case other => Seq("$signed(", other, ")")
+ }
+ def castIf(e: Expression, isFirst: Boolean = false): Any = {
+ if (doprim.args.exists(_.tpe.isInstanceOf[SIntType])) {
+ e.tpe match {
+ case _: SIntType => doCast(e)
+ case _ => throwInternalError(s"Unexpected non-SInt type for $e in $doprim")
+ }
+ } else {
+ parenthesize(e, isFirst)
+ }
+ }
+ def cast(e: Expression, isFirst: Boolean = false): Any = doprim.tpe match {
+ case _: UIntType => parenthesize(e, isFirst)
+ case _: SIntType => doCast(e)
+ case _ => throwInternalError(s"Unexpected type for $e in $doprim")
+ }
+ def castAs(e: Expression, isFirst: Boolean = false): Any = e.tpe match {
+ case _: UIntType => parenthesize(e, isFirst)
+ case _: SIntType => doCast(e)
+ case _ => throwInternalError(s"Unexpected type for $e in $doprim")
+ }
+ def a0: Expression = doprim.args.head
+ def a1: Expression = doprim.args(1)
+ def c0: Int = doprim.consts.head.toInt
+ def c1: Int = doprim.consts(1).toInt
+
+ def castCatArgs(a0: Expression, a1: Expression): Seq[Any] = {
+ val a0Seq = a0 match {
+ case cat @ DoPrim(PrimOps.Cat, args, _, _) => castCatArgs(args.head, args(1))
+ case _ => Seq(cast(a0))
+ }
+ val a1Seq = a1 match {
+ case cat @ DoPrim(PrimOps.Cat, args, _, _) => castCatArgs(args.head, args(1))
+ case _ => Seq(cast(a1))
+ }
+ a0Seq ++ Seq(",") ++ a1Seq
+ }
+
+ doprim.op match {
+ case Add => Seq(castIf(a0, true), " + ", castIf(a1))
+ case Addw => Seq(castIf(a0, true), " + ", castIf(a1))
+ case Sub => Seq(castIf(a0, true), " - ", castIf(a1))
+ case Subw => Seq(castIf(a0, true), " - ", castIf(a1))
+ case Mul => Seq(castIf(a0, true), " * ", castIf(a1))
+ case Div => Seq(castIf(a0, true), " / ", castIf(a1))
+ case Rem => Seq(castIf(a0, true), " % ", castIf(a1))
+ case Lt => Seq(castIf(a0, true), " < ", castIf(a1))
+ case Leq => Seq(castIf(a0, true), " <= ", castIf(a1))
+ case Gt => Seq(castIf(a0, true), " > ", castIf(a1))
+ case Geq => Seq(castIf(a0, true), " >= ", castIf(a1))
+ case Eq => Seq(castIf(a0, true), " == ", castIf(a1))
+ case Neq => Seq(castIf(a0, true), " != ", castIf(a1))
+ case Pad =>
+ val w = bitWidth(a0.tpe)
+ val diff = c0 - w
+ if (w == BigInt(0) || diff <= 0) Seq(a0)
+ else
+ doprim.tpe match {
+ // Either sign extend or zero extend.
+ // If width == BigInt(1), don't extract bit
+ case (_: SIntType) if w == BigInt(1) => Seq("{", c0, "{", a0, "}}")
+ case (_: SIntType) => Seq("{{", diff, "{", parenthesize(a0, true), "[", w - 1, "]}},", a0, "}")
+ case (_) => Seq("{{", diff, "'d0}, ", a0, "}")
+ }
+ // Because we don't support complex Expressions, all casts are ignored
+ // This simplifies handling of assignment of a signed expression to an unsigned LHS value
+ // which does not require a cast in Verilog
+ case AsUInt | AsSInt | AsClock | AsAsyncReset => Seq(a0)
+ case Dshlw => Seq(cast(a0), " << ", parenthesize(a1, false))
+ case Dshl => Seq(cast(a0), " << ", parenthesize(a1, false))
+ case Dshr =>
+ doprim.tpe match {
+ case (_: SIntType) => Seq(cast(a0), " >>> ", parenthesize(a1, false))
+ case (_) => Seq(cast(a0), " >> ", parenthesize(a1, false))
+ }
+ case Shl => if (c0 > 0) Seq("{", cast(a0), s", $c0'h0}") else Seq(cast(a0))
+ case Shr if c0 >= bitWidth(a0.tpe) =>
+ error("Verilog emitter does not support SHIFT_RIGHT >= arg width")
+ case Shr if c0 == (bitWidth(a0.tpe) - 1) => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - 1, "]")
+ case Shr => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - 1, ":", c0, "]")
+ case Neg => Seq("-", cast(a0, true))
+ case Cvt =>
+ a0.tpe match {
+ case (_: UIntType) => Seq("{1'b0,", cast(a0), "}")
+ case (_: SIntType) => Seq(cast(a0))
+ }
+ case Not => Seq("~", parenthesize(a0, true))
+ case And => Seq(castAs(a0, true), " & ", castAs(a1))
+ case Or => Seq(castAs(a0, true), " | ", castAs(a1))
+ case Xor => Seq(castAs(a0, true), " ^ ", castAs(a1))
+ case Andr => Seq("&", cast(a0, true))
+ case Orr => Seq("|", cast(a0, true))
+ case Xorr => Seq("^", cast(a0, true))
+ case Cat => "{" +: (castCatArgs(a0, a1) :+ "}")
+ // If selecting zeroth bit and single-bit wire, just emit the wire
+ case Bits if c0 == 0 && c1 == 0 && bitWidth(a0.tpe) == BigInt(1) => Seq(a0)
+ case Bits if c0 == c1 => Seq(parenthesize(a0, true), "[", c0, "]")
+ case Bits => Seq(parenthesize(a0, true), "[", c0, ":", c1, "]")
+ // If selecting zeroth bit and single-bit wire, just emit the wire
+ case Head if c0 == 1 && bitWidth(a0.tpe) == BigInt(1) => Seq(a0)
+ case Head if c0 == 1 => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - 1, "]")
+ case Head =>
+ val msb = bitWidth(a0.tpe) - 1
+ val lsb = bitWidth(a0.tpe) - c0
+ Seq(parenthesize(a0, true), "[", msb, ":", lsb, "]")
+ case Tail if c0 == (bitWidth(a0.tpe) - 1) => Seq(parenthesize(a0, true), "[0]")
+ case Tail => Seq(parenthesize(a0, true), "[", bitWidth(a0.tpe) - c0 - 1, ":0]")
+ }
+ }
+
+ /**
+ * Gets a reference to a verilog renderer. This is used by the current standard verilog emission process
+ * but allows access to individual portions, in particular, this function can be used to generate
+ * the header for a verilog file without generating anything else.
+ *
+ * @param m the start module
+ * @param moduleMap a way of finding other modules
+ * @param writer where rendering will be placed
+ * @return the render reference
+ */
+ def getRenderer(m: Module, moduleMap: Map[String, DefModule])(implicit writer: Writer): VerilogRender = {
+ new VerilogRender(m, moduleMap)(writer)
+ }
+
+ /**
+ * Gets a reference to a verilog renderer. This is used by the current standard verilog emission process
+ * but allows access to individual portions, in particular, this function can be used to generate
+ * the header for a verilog file without generating anything else.
+ *
+ * @param descriptions comments to be emitted
+ * @param m the start module
+ * @param moduleMap a way of finding other modules
+ * @param writer where rendering will be placed
+ * @return the render reference
+ */
+ def getRenderer(
+ descriptions: Seq[DescriptionAnnotation],
+ m: Module,
+ moduleMap: Map[String, DefModule]
+ )(
+ implicit writer: Writer
+ ): VerilogRender = {
+ val newMod = new AddDescriptionNodes().executeModule(m, descriptions)
+
+ newMod match {
+ case DescribedMod(d, pds, m: Module) =>
+ new VerilogRender(d, pds, m, moduleMap, "", new EmissionOptions(Seq.empty))(writer)
+ case m: Module => new VerilogRender(m, moduleMap)(writer)
+ }
+ }
+
+ def addFormalStatement(
+ formals: mutable.Map[Expression, ArrayBuffer[Seq[Any]]],
+ clk: Expression,
+ en: Expression,
+ stmt: Seq[Any],
+ info: Info,
+ msg: StringLit
+ ): Unit = {
+ throw EmitterException(
+ "Cannot emit verification statements in Verilog" +
+ "(2001). Use the SystemVerilog emitter instead."
+ )
+ }
+
+ /**
+ * Store Emission option per Target
+ * Guarantee only one emission option per Target
+ */
+ private[firrtl] class EmissionOptionMap[V <: EmissionOption](val df: V) {
+ private val m = collection.mutable.HashMap[ReferenceTarget, V]().withDefaultValue(df)
+ def +=(elem: (ReferenceTarget, V)): EmissionOptionMap.this.type = {
+ if (m.contains(elem._1))
+ throw EmitterException(s"Multiple EmissionOption for the target ${elem._1} (${m(elem._1)} ; ${elem._2})")
+ m += (elem)
+ this
+ }
+ def apply(key: ReferenceTarget): V = m.apply(key)
+ }
+
+ /** Provide API to retrieve EmissionOptions based on the provided [[AnnotationSeq]]
+ *
+ * @param annotations : AnnotationSeq to be searched for EmissionOptions
+ */
+ private[firrtl] class EmissionOptions(annotations: AnnotationSeq) {
+ // Private so that we can present an immutable API
+ private val memoryEmissionOption = new EmissionOptionMap[MemoryEmissionOption](MemoryEmissionOptionDefault)
+ private val registerEmissionOption = new EmissionOptionMap[RegisterEmissionOption](RegisterEmissionOptionDefault)
+ private val wireEmissionOption = new EmissionOptionMap[WireEmissionOption](WireEmissionOptionDefault)
+ private val portEmissionOption = new EmissionOptionMap[PortEmissionOption](PortEmissionOptionDefault)
+ private val nodeEmissionOption = new EmissionOptionMap[NodeEmissionOption](NodeEmissionOptionDefault)
+ private val connectEmissionOption = new EmissionOptionMap[ConnectEmissionOption](ConnectEmissionOptionDefault)
+
+ def getMemoryEmissionOption(target: ReferenceTarget): MemoryEmissionOption =
+ memoryEmissionOption(target)
+
+ def getRegisterEmissionOption(target: ReferenceTarget): RegisterEmissionOption =
+ registerEmissionOption(target)
+
+ def getWireEmissionOption(target: ReferenceTarget): WireEmissionOption =
+ wireEmissionOption(target)
+
+ def getPortEmissionOption(target: ReferenceTarget): PortEmissionOption =
+ portEmissionOption(target)
+
+ def getNodeEmissionOption(target: ReferenceTarget): NodeEmissionOption =
+ nodeEmissionOption(target)
+
+ def getConnectEmissionOption(target: ReferenceTarget): ConnectEmissionOption =
+ connectEmissionOption(target)
+
+ private val emissionAnnos = annotations.collect {
+ case m: SingleTargetAnnotation[ReferenceTarget] @unchecked with EmissionOption => m
+ }
+ // using multiple foreach instead of a single partial function as an Annotation can gather multiple EmissionOptions for simplicity
+ emissionAnnos.foreach {
+ case a: MemoryEmissionOption => memoryEmissionOption += ((a.target, a))
+ case _ =>
+ }
+ emissionAnnos.foreach {
+ case a: RegisterEmissionOption => registerEmissionOption += ((a.target, a))
+ case _ =>
+ }
+ emissionAnnos.foreach {
+ case a: WireEmissionOption => wireEmissionOption += ((a.target, a))
+ case _ =>
+ }
+ emissionAnnos.foreach {
+ case a: PortEmissionOption => portEmissionOption += ((a.target, a))
+ case _ =>
+ }
+ emissionAnnos.foreach {
+ case a: NodeEmissionOption => nodeEmissionOption += ((a.target, a))
+ case _ =>
+ }
+ emissionAnnos.foreach {
+ case a: ConnectEmissionOption => connectEmissionOption += ((a.target, a))
+ case _ =>
+ }
+ }
+
+ /**
+ * Used by getRenderer, it has machinery to produce verilog from IR.
+ * Making this a class allows access to particular parts of the verilog emission.
+ *
+ * @param description a description of the start module
+ * @param portDescriptions a map of port name to description
+ * @param m the start module
+ * @param moduleMap a map of modules so submodules can be discovered
+ * @param writer where rendered information is placed.
+ */
+ class VerilogRender(
+ description: Seq[Description],
+ portDescriptions: Map[String, Seq[Description]],
+ m: Module,
+ moduleMap: Map[String, DefModule],
+ circuitName: String,
+ emissionOptions: EmissionOptions
+ )(
+ implicit writer: Writer) {
+
+ def this(
+ m: Module,
+ moduleMap: Map[String, DefModule],
+ circuitName: String,
+ emissionOptions: EmissionOptions
+ )(
+ implicit writer: Writer
+ ) = {
+ this(Seq(), Map.empty, m, moduleMap, circuitName, emissionOptions)(writer)
+ }
+ def this(m: Module, moduleMap: Map[String, DefModule])(implicit writer: Writer) = {
+ this(Seq(), Map.empty, m, moduleMap, "", new EmissionOptions(Seq.empty))(writer)
+ }
+
+ val netlist = mutable.LinkedHashMap[WrappedExpression, InfoExpr]()
+ val namespace = Namespace(m)
+ namespace.newName("_RAND") // Start rand names at _RAND_0
+ def build_netlist(s: Statement): Unit = {
+ s.foreach(build_netlist)
+ s match {
+ case sx: Connect => netlist(sx.loc) = InfoExpr(sx.info, sx.expr)
+ case sx: IsInvalid => error("Should have removed these!")
+ // TODO Since only register update and memories use the netlist anymore, I think nodes are
+ // unnecessary
+ case sx: DefNode =>
+ val e = WRef(sx.name, sx.value.tpe, NodeKind, SourceFlow)
+ netlist(e) = InfoExpr(sx.info, sx.value)
+ case _ =>
+ }
+ }
+
+ val portdefs = ArrayBuffer[Seq[Any]]()
+ // maps ifdef guard to declaration blocks
+ val ifdefDeclares: mutable.Map[String, ArrayBuffer[Seq[Any]]] = mutable.Map().withDefault { key =>
+ val value = ArrayBuffer[Seq[Any]]()
+ ifdefDeclares(key) = value
+ value
+ }
+ val declares = ArrayBuffer[Seq[Any]]()
+ val instdeclares = ArrayBuffer[Seq[Any]]()
+ val assigns = ArrayBuffer[Seq[Any]]()
+ val attachSynAssigns = ArrayBuffer.empty[Seq[Any]]
+ val attachAliases = ArrayBuffer.empty[Seq[Any]]
+ // No (aka synchronous) always blocks, keyed by clock
+ val noResetAlwaysBlocks = mutable.LinkedHashMap[Expression, ArrayBuffer[Seq[Any]]]()
+ // One always block per async reset register, (Clock, Reset, Content)
+ // An alternative approach is to have one always block per combination of clock and async reset,
+ // but Formality doesn't allow more than 1 statement inside async reset always blocks
+ val asyncResetAlwaysBlocks = mutable.ArrayBuffer[(Expression, Expression, Seq[Any])]()
+ // Used to determine type of initvar for initializing memories
+ var maxMemSize: BigInt = BigInt(0)
+ // maps ifdef guard to initial blocks
+ val ifdefInitials: mutable.Map[String, ArrayBuffer[Seq[Any]]] = mutable.Map().withDefault { key =>
+ val value = ArrayBuffer[Seq[Any]]()
+ ifdefInitials(key) = value
+ value
+ }
+ val initials = ArrayBuffer[Seq[Any]]()
+ // In Verilog, async reset registers are expressed using always blocks of the form:
+ // always @(posedge clock or posedge reset) begin
+ // if (reset) ...
+ // There is a fundamental mismatch between this representation which treats async reset
+ // registers as edge-triggered when in reality they are level-triggered.
+ // When not randomized, there is no mismatch because the async reset transition at the start
+ // of simulation from X to 1 triggers the posedge block for async reset.
+ // When randomized, this can result in silicon-simulation mismatch when async reset is held high
+ // upon power on with no clock, then async reset is dropped before the clock starts. In this
+ // circumstance, the async reset register will be randomized in simulation instead of being
+ // reset. To fix this, we need extra initial block logic to reset async reset registers again
+ // post-randomize.
+ val asyncInitials = ArrayBuffer[Seq[Any]]()
+ // memories need to be initialized even when randomization is disabled
+ val memoryInitials = ArrayBuffer[Seq[Any]]()
+ val simulates = ArrayBuffer[Seq[Any]]()
+ val formals = mutable.LinkedHashMap[Expression, ArrayBuffer[Seq[Any]]]()
+
+ def bigIntToVLit(bi: BigInt): String =
+ if (bi.isValidInt) bi.toString else s"${bi.bitLength}'d$bi"
+
+ // declare vector type with no preset and optionally with an ifdef guard
+ private def declareVectorType(
+ b: String,
+ n: String,
+ tpe: Type,
+ size: BigInt,
+ info: Info,
+ ifdefOpt: Option[String]
+ ): Unit = {
+ val decl = Seq(b, " ", tpe, " ", n, " [0:", bigIntToVLit(size - 1), "];", info)
+ if (ifdefOpt.isDefined) {
+ ifdefDeclares(ifdefOpt.get) += decl
+ } else {
+ declares += decl
+ }
+ }
+
+ // original vector type declare without initial value
+ def declareVectorType(b: String, n: String, tpe: Type, size: BigInt, info: Info): Unit =
+ declareVectorType(b, n, tpe, size, info, None)
+
+ // declare vector type with initial value
+ def declareVectorType(b: String, n: String, tpe: Type, size: BigInt, info: Info, preset: Expression): Unit = {
+ declares += Seq(b, " ", tpe, " ", n, " [0:", bigIntToVLit(size - 1), "] = ", preset, ";", info)
+ }
+
+ val moduleTarget = CircuitTarget(circuitName).module(m.name)
+
+ // declare with initial value
+ def declare(b: String, n: String, t: Type, info: Info, preset: Expression) = t match {
+ case tx: VectorType =>
+ declareVectorType(b, n, tx.tpe, tx.size, info, preset)
+ case tx =>
+ declares += Seq(b, " ", tx, " ", n, " = ", preset, ";", info)
+ }
+
+ // original declare without initial value and optinally with an ifdef guard
+ private def declare(b: String, n: String, t: Type, info: Info, ifdefOpt: Option[String]): Unit = t match {
+ case tx: VectorType =>
+ declareVectorType(b, n, tx.tpe, tx.size, info, ifdefOpt)
+ case tx =>
+ val decl = Seq(b, " ", tx, " ", n, ";", info)
+ if (ifdefOpt.isDefined) {
+ ifdefDeclares(ifdefOpt.get) += decl
+ } else {
+ declares += decl
+ }
+ }
+
+ // original declare without initial value and with an ifdef guard
+ private def declare(b: String, n: String, t: Type, info: Info, ifdef: String): Unit =
+ declare(b, n, t, info, Some(ifdef))
+
+ // original declare without initial value
+ def declare(b: String, n: String, t: Type, info: Info): Unit =
+ declare(b, n, t, info, None)
+
+ def assign(e: Expression, infoExpr: InfoExpr): Unit =
+ assign(e, infoExpr.expr, infoExpr.info)
+
+ def assign(e: Expression, value: Expression, info: Info): Unit = {
+ assigns += Seq("assign ", e, " = ", value, ";", info)
+ }
+
+ // In simulation, assign garbage under a predicate
+ def garbageAssign(e: Expression, syn: Expression, garbageCond: Expression, info: Info) = {
+ assigns += Seq("`ifndef RANDOMIZE_GARBAGE_ASSIGN")
+ assigns += Seq("assign ", e, " = ", syn, ";", info)
+ assigns += Seq("`else")
+ assigns += Seq(
+ "assign ",
+ e,
+ " = ",
+ garbageCond,
+ " ? ",
+ rand_string(syn.tpe, "RANDOMIZE_GARBAGE_ASSIGN"),
+ " : ",
+ syn,
+ ";",
+ info
+ )
+ assigns += Seq("`endif // RANDOMIZE_GARBAGE_ASSIGN")
+ }
+
+ def invalidAssign(e: Expression) = {
+ assigns += Seq("`ifdef RANDOMIZE_INVALID_ASSIGN")
+ assigns += Seq("assign ", e, " = ", rand_string(e.tpe, "RANDOMIZE_INVALID_ASSIGN"), ";")
+ assigns += Seq("`endif // RANDOMIZE_INVALID_ASSIGN")
+ }
+
+ def regUpdate(r: Expression, clk: Expression, reset: Expression, init: Expression) = {
+ def addUpdate(info: Info, expr: Expression, tabs: Seq[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")
+
+ val (eninfo, tinfo, finfo) = MultiInfo.demux(info)
+ lazy val _if = Seq(tabs, "if (", m.cond, ") begin", eninfo)
+ lazy val _else = Seq(tabs, "end else begin")
+ lazy val _ifNot = Seq(tabs, "if (!(", m.cond, ")) begin", eninfo)
+ lazy val _end = Seq(tabs, "end")
+ lazy val _true = addUpdate(tinfo, m.tval, tab +: tabs)
+ lazy val _false = addUpdate(finfo, m.fval, tab +: tabs)
+ lazy val _elseIfFalse = {
+ val _falsex = addUpdate(finfo, 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, with one subcase for asynchronous reset:
+ * 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
+ * a) The reset is asynchronous; emit both 'if' and a trivial 'else' to avoid latches
+ * b) The reset is synchronous; 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) =>
+ m.cond.tpe match {
+ case AsyncResetType => (_if +: _true :+ _else) ++ _true :+ _end
+ case _ => _if +: _true :+ _end
+ }
+ case (_, _: Mux) => (_if +: _true) ++ _elseIfFalse
+ case _ => (_if +: _true :+ _else) ++ _false :+ _end
+ }
+ case e => Seq(Seq(tabs, r, " <= ", e, ";", info))
+ }
+ if (weq(init, r)) { // Synchronous Reset
+ val InfoExpr(info, e) = netlist(r)
+ noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]()) ++= addUpdate(info, e, Seq.empty)
+ } else { // Asynchronous Reset
+ assert(reset.tpe == AsyncResetType, "Error! Synchronous reset should have been removed!")
+ val tv = init
+ val InfoExpr(finfo, fv) = netlist(r)
+ // TODO add register info argument and build a MultiInfo to pass
+ asyncResetAlwaysBlocks += (
+ (
+ clk,
+ reset,
+ addUpdate(NoInfo, Mux(reset, tv, fv, mux_type_and_widths(tv, fv)), Seq.empty)
+ )
+ )
+ }
+ }
+
+ def update(e: Expression, value: Expression, clk: Expression, en: Expression, info: Info) = {
+ val lines = noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
+ if (weq(en, one)) lines += Seq(e, " <= ", value, ";")
+ else {
+ lines += Seq("if(", en, ") begin")
+ lines += Seq(tab, e, " <= ", value, ";", info)
+ lines += Seq("end")
+ }
+ }
+
+ // Declares an intermediate wire to hold a large enough random number.
+ // Then, return the correct number of bits selected from the random value
+ def rand_string(t: Type, ifdefOpt: Option[String]): Seq[Any] = {
+ val nx = namespace.newName("_RAND")
+ val rand = VRandom(bitWidth(t))
+ val tx = SIntType(IntWidth(rand.realWidth))
+ declare("reg", nx, tx, NoInfo, ifdefOpt)
+ val initial = Seq(wref(nx, tx), " = ", VRandom(bitWidth(t)), ";")
+ if (ifdefOpt.isDefined) {
+ ifdefInitials(ifdefOpt.get) += initial
+ } else {
+ initials += initial
+ }
+ Seq(nx, "[", bitWidth(t) - 1, ":0]")
+ }
+
+ def rand_string(t: Type, ifdef: String): Seq[Any] = rand_string(t, Some(ifdef))
+
+ def rand_string(t: Type): Seq[Any] = rand_string(t, None)
+
+ def initialize(e: Expression, reset: Expression, init: Expression) = {
+ val randString = rand_string(e.tpe, "RANDOMIZE_REG_INIT")
+ ifdefInitials("RANDOMIZE_REG_INIT") += Seq(e, " = ", randString, ";")
+ reset.tpe match {
+ case AsyncResetType =>
+ asyncInitials += Seq("if (", reset, ") begin")
+ asyncInitials += Seq(tab, e, " = ", init, ";")
+ asyncInitials += Seq("end")
+ case _ => // do nothing
+ }
+ }
+
+ def initialize_mem(s: DefMemory, opt: MemoryEmissionOption): Unit = {
+ if (s.depth > maxMemSize) {
+ maxMemSize = s.depth
+ }
+
+ val dataWidth = bitWidth(s.dataType)
+ val maxDataValue = (BigInt(1) << dataWidth.toInt) - 1
+
+ def checkValueRange(value: BigInt, at: String): Unit = {
+ if (value < 0) throw EmitterException(s"Memory ${at} cannot be initialized with negative value: $value")
+ if (value > maxDataValue)
+ throw EmitterException(s"Memory ${at} cannot be initialized with value: $value. Too large (> $maxDataValue)!")
+ }
+
+ opt.initValue match {
+ case MemoryArrayInit(values) =>
+ if (values.length != s.depth)
+ throw EmitterException(
+ s"Memory ${s.name} of depth ${s.depth} cannot be initialized with an array of length ${values.length}!"
+ )
+ val memName = LowerTypes.loweredName(wref(s.name, s.dataType))
+ values.zipWithIndex.foreach {
+ case (value, addr) =>
+ checkValueRange(value, s"${s.name}[$addr]")
+ val access = s"$memName[${bigIntToVLit(addr)}]"
+ memoryInitials += Seq(access, " = ", bigIntToVLit(value), ";")
+ }
+ case MemoryScalarInit(value) =>
+ checkValueRange(value, s.name)
+ // note: s.dataType is the incorrect type for initvar, but it is ignored in the serialization
+ val index = wref("initvar", s.dataType)
+ memoryInitials += Seq("for (initvar = 0; initvar < ", bigIntToVLit(s.depth), "; initvar = initvar+1)")
+ memoryInitials += Seq(
+ tab,
+ WSubAccess(wref(s.name, s.dataType), index, s.dataType, SinkFlow),
+ " = ",
+ bigIntToVLit(value),
+ ";"
+ )
+ case MemoryRandomInit =>
+ // note: s.dataType is the incorrect type for initvar, but it is ignored in the serialization
+ val index = wref("initvar", s.dataType)
+ val rstring = rand_string(s.dataType, "RANDOMIZE_MEM_INIT")
+ ifdefInitials("RANDOMIZE_MEM_INIT") += Seq(
+ "for (initvar = 0; initvar < ",
+ bigIntToVLit(s.depth),
+ "; initvar = initvar+1)"
+ )
+ ifdefInitials("RANDOMIZE_MEM_INIT") += Seq(
+ tab,
+ WSubAccess(wref(s.name, s.dataType), index, s.dataType, SinkFlow),
+ " = ",
+ rstring,
+ ";"
+ )
+ }
+ }
+
+ def simulate(clk: Expression, en: Expression, s: Seq[Any], cond: Option[String], info: Info) = {
+ val lines = noResetAlwaysBlocks.getOrElseUpdate(clk, ArrayBuffer[Seq[Any]]())
+ lines += Seq("`ifndef SYNTHESIS")
+ if (cond.nonEmpty) {
+ lines += Seq(s"`ifdef ${cond.get}")
+ lines += Seq(tab, s"if (`${cond.get}) begin")
+ lines += Seq("`endif")
+ }
+ lines += Seq(tab, tab, "if (", en, ") begin")
+ lines += Seq(tab, tab, tab, s, info)
+ lines += Seq(tab, tab, "end")
+ if (cond.nonEmpty) {
+ lines += Seq(s"`ifdef ${cond.get}")
+ lines += Seq(tab, "end")
+ lines += Seq("`endif")
+ }
+ lines += Seq("`endif // SYNTHESIS")
+ }
+
+ def addFormal(clk: Expression, en: Expression, stmt: Seq[Any], info: Info, msg: StringLit): Unit = {
+ addFormalStatement(formals, clk, en, stmt, info, msg)
+ }
+
+ def formalStatement(op: Formal.Value, cond: Expression): Seq[Any] = {
+ Seq(op.toString, "(", cond, ");")
+ }
+
+ def stop(ret: Int): Seq[Any] = Seq(if (ret == 0) "$finish;" else "$fatal;")
+
+ def printf(str: StringLit, args: Seq[Expression]): Seq[Any] = {
+ val strx = str.verilogEscape +: args.flatMap(Seq(",", _))
+ Seq("$fwrite(32'h80000002,", strx, ");")
+ }
+
+ // turn strings into Seq[String] verilog comments
+ def build_comment(desc: String): Seq[Seq[String]] = {
+ val lines = desc.split("\n").toSeq
+
+ if (lines.size > 1) {
+ val lineSeqs = lines.tail.map {
+ case "" => Seq(" *")
+ case nonEmpty => Seq(" * ", nonEmpty)
+ }
+ Seq("/* ", lines.head) +: lineSeqs :+ Seq(" */")
+ } else {
+ Seq(Seq("// ", lines(0)))
+ }
+ }
+
+ def build_attribute(attrs: String): Seq[Seq[String]] = {
+ Seq(Seq("(* ") ++ Seq(attrs) ++ Seq(" *)"))
+ }
+
+ // Turn ports into Seq[String] and add to portdefs
+ def build_ports(): Unit = {
+ def padToMax(strs: Seq[String]): Seq[String] = {
+ val len = if (strs.nonEmpty) strs.map(_.length).max else 0
+ strs.map(_.padTo(len, ' '))
+ }
+
+ // Turn directions into strings (and AnalogType into inout)
+ val dirs = m.ports.map {
+ case Port(_, name, dir, tpe) =>
+ (dir, tpe) match {
+ case (_, AnalogType(_)) => "inout " // padded to length of output
+ case (Input, _) => "input "
+ case (Output, _) => "output"
+ }
+ }
+ // Turn types into strings, all ports must be GroundTypes
+ val tpes = m.ports.map {
+ case Port(_, _, _, tpe: GroundType) => stringify(tpe)
+ case port: Port => error(s"Trying to emit non-GroundType Port $port")
+ }
+
+ // dirs are already padded
+ (dirs, padToMax(tpes), m.ports).zipped.toSeq.zipWithIndex.foreach {
+ case ((dir, tpe, Port(info, name, _, _)), i) =>
+ portDescriptions.get(name).map {
+ case d =>
+ portdefs += Seq("")
+ portdefs ++= build_description(d)
+ }
+
+ if (i != m.ports.size - 1) {
+ portdefs += Seq(dir, " ", tpe, " ", name, ",", info)
+ } else {
+ portdefs += Seq(dir, " ", tpe, " ", name, info)
+ }
+ }
+ }
+
+ def build_description(d: Seq[Description]): Seq[Seq[String]] = d.flatMap {
+ case DocString(desc) => build_comment(desc.string)
+ case Attribute(attr) => build_attribute(attr.string)
+ }
+
+ def build_streams(s: Statement): Unit = {
+ val withoutDescription = s match {
+ case DescribedStmt(d, stmt) =>
+ stmt match {
+ case sx: IsDeclaration =>
+ declares ++= build_description(d)
+ case _ =>
+ }
+ stmt
+ case stmt => stmt
+ }
+ withoutDescription.foreach(build_streams)
+ withoutDescription match {
+ case sx @ Connect(info, loc @ WRef(_, _, PortKind | WireKind | InstanceKind, _), expr) =>
+ assign(loc, expr, info)
+ case sx: DefWire =>
+ declare("wire", sx.name, sx.tpe, sx.info)
+ case sx: DefRegister =>
+ val options = emissionOptions.getRegisterEmissionOption(moduleTarget.ref(sx.name))
+ val e = wref(sx.name, sx.tpe)
+ if (options.useInitAsPreset) {
+ declare("reg", sx.name, sx.tpe, sx.info, sx.init)
+ regUpdate(e, sx.clock, sx.reset, e)
+ } else {
+ declare("reg", sx.name, sx.tpe, sx.info)
+ regUpdate(e, sx.clock, sx.reset, sx.init)
+ }
+ if (!options.disableRandomization)
+ initialize(e, sx.reset, sx.init)
+ case sx: DefNode =>
+ declare("wire", sx.name, sx.value.tpe, sx.info, sx.value)
+ case sx: Stop =>
+ simulate(sx.clk, sx.en, stop(sx.ret), Some("STOP_COND"), sx.info)
+ case sx: Print =>
+ simulate(sx.clk, sx.en, printf(sx.string, sx.args), Some("PRINTF_COND"), sx.info)
+ case sx: Verification =>
+ addFormal(sx.clk, sx.en, formalStatement(sx.op, sx.pred), sx.info, sx.msg)
+ // If we are emitting an Attach, it must not have been removable in VerilogPrep
+ case sx: Attach =>
+ // For Synthesis
+ // Note that this is quadratic in the number of things attached
+ for (set <- sx.exprs.toSet.subsets(2)) {
+ val (a, b) = set.toSeq match {
+ case Seq(x, y) => (x, y)
+ }
+ // Synthesizable ones as well
+ attachSynAssigns += Seq("assign ", a, " = ", b, ";", sx.info)
+ attachSynAssigns += Seq("assign ", b, " = ", a, ";", sx.info)
+ }
+ // alias implementation for everything else
+ attachAliases += Seq("alias ", sx.exprs.flatMap(e => Seq(e, " = ")).init, ";", sx.info)
+ case sx: WDefInstanceConnector =>
+ val (module, params) = moduleMap(sx.module) match {
+ case DescribedMod(_, _, ExtModule(_, _, _, extname, params)) => (extname, params)
+ case DescribedMod(_, _, Module(_, name, _, _)) => (name, Seq.empty)
+ case ExtModule(_, _, _, extname, params) => (extname, params)
+ case Module(_, name, _, _) => (name, Seq.empty)
+ }
+ val ps = if (params.nonEmpty) params.map(stringify).mkString("#(", ", ", ") ") else ""
+ instdeclares += Seq(module, " ", ps, sx.name, " (", sx.info)
+ for (((port, ref), i) <- sx.portCons.zipWithIndex) {
+ val line = Seq(tab, ".", remove_root(port), "(", ref, ")")
+ if (i != sx.portCons.size - 1) instdeclares += Seq(line, ",")
+ else instdeclares += line
+ }
+ instdeclares += Seq(");")
+ case sx: DefMemory =>
+ val options = emissionOptions.getMemoryEmissionOption(moduleTarget.ref(sx.name))
+ val fullSize = sx.depth * (sx.dataType match {
+ case GroundType(IntWidth(width)) => width
+ })
+ val decl = if (fullSize > (1 << 29)) "reg /* sparse */" else "reg"
+ declareVectorType(decl, sx.name, sx.dataType, sx.depth, sx.info)
+ initialize_mem(sx, options)
+ if (sx.readLatency != 0 || sx.writeLatency != 1)
+ throw EmitterException(
+ "All memories should be transformed into " +
+ "blackboxes or combinational by previous passses"
+ )
+ for (r <- sx.readers) {
+ val data = memPortField(sx, r, "data")
+ val addr = memPortField(sx, r, "addr")
+ // Ports should share an always@posedge, so can't have intermediary wire
+
+ declare("wire", LowerTypes.loweredName(data), data.tpe, sx.info)
+ declare("wire", LowerTypes.loweredName(addr), addr.tpe, sx.info)
+ // declare("wire", LowerTypes.loweredName(en), en.tpe)
+
+ //; Read port
+ assign(addr, netlist(addr))
+ // assign(en, netlist(en)) //;Connects value to m.r.en
+ val mem = WRef(sx.name, memType(sx), MemKind, UnknownFlow)
+ val memPort = WSubAccess(mem, addr, sx.dataType, UnknownFlow)
+ val depthValue = UIntLiteral(sx.depth, IntWidth(sx.depth.bitLength))
+ val garbageGuard = DoPrim(Geq, Seq(addr, depthValue), Seq(), UnknownType)
+
+ if ((sx.depth & (sx.depth - 1)) == 0)
+ assign(data, memPort, sx.info)
+ else
+ garbageAssign(data, memPort, garbageGuard, sx.info)
+ }
+
+ for (w <- sx.writers) {
+ val data = memPortField(sx, w, "data")
+ val addr = memPortField(sx, w, "addr")
+ val mask = memPortField(sx, w, "mask")
+ val en = memPortField(sx, w, "en")
+ //Ports should share an always@posedge, so can't have intermediary wire
+ // TODO should we use the info here for anything?
+ val InfoExpr(_, clk) = netlist(memPortField(sx, w, "clk"))
+
+ declare("wire", LowerTypes.loweredName(data), data.tpe, sx.info)
+ declare("wire", LowerTypes.loweredName(addr), addr.tpe, sx.info)
+ declare("wire", LowerTypes.loweredName(mask), mask.tpe, sx.info)
+ declare("wire", LowerTypes.loweredName(en), en.tpe, sx.info)
+
+ // Write port
+ assign(data, netlist(data))
+ assign(addr, netlist(addr))
+ assign(mask, netlist(mask))
+ assign(en, netlist(en))
+
+ val mem = WRef(sx.name, memType(sx), MemKind, UnknownFlow)
+ val memPort = WSubAccess(mem, addr, sx.dataType, UnknownFlow)
+ update(memPort, data, clk, AND(en, mask), sx.info)
+ }
+
+ if (sx.readwriters.nonEmpty)
+ throw EmitterException(
+ "All readwrite ports should be transformed into " +
+ "read & write ports by previous passes"
+ )
+ case _ =>
+ }
+ }
+
+ def emit_streams(): Unit = {
+ build_description(description).foreach(emit(_))
+ emit(Seq("module ", m.name, "(", m.info))
+ for (x <- portdefs) emit(Seq(tab, x))
+ emit(Seq(");"))
+
+ ifdefDeclares.toSeq.sortWith(_._1 < _._1).foreach {
+ case (ifdef, declares) =>
+ emit(Seq("`ifdef " + ifdef))
+ for (x <- declares) emit(Seq(tab, x))
+ emit(Seq("`endif // " + ifdef))
+ }
+ for (x <- declares) emit(Seq(tab, x))
+ for (x <- instdeclares) emit(Seq(tab, x))
+ for (x <- assigns) emit(Seq(tab, x))
+ if (attachAliases.nonEmpty) {
+ emit(Seq("`ifdef SYNTHESIS"))
+ for (x <- attachSynAssigns) emit(Seq(tab, x))
+ emit(Seq("`elsif verilator"))
+ emit(
+ Seq(
+ tab,
+ "`error \"Verilator does not support alias and thus cannot arbirarily connect bidirectional wires and ports\""
+ )
+ )
+ emit(Seq("`else"))
+ for (x <- attachAliases) emit(Seq(tab, x))
+ emit(Seq("`endif"))
+ }
+
+ for ((clk, content) <- noResetAlwaysBlocks if content.nonEmpty) {
+ emit(Seq(tab, "always @(posedge ", clk, ") begin"))
+ for (line <- content) emit(Seq(tab, tab, line))
+ emit(Seq(tab, "end"))
+ }
+
+ for ((clk, reset, content) <- asyncResetAlwaysBlocks if content.nonEmpty) {
+ emit(Seq(tab, "always @(posedge ", clk, " or posedge ", reset, ") begin"))
+ for (line <- content) emit(Seq(tab, tab, line))
+ emit(Seq(tab, "end"))
+ }
+
+ if (initials.nonEmpty || ifdefInitials.nonEmpty || memoryInitials.nonEmpty) {
+ emit(Seq("// Register and memory initialization"))
+ emit(Seq("`ifdef RANDOMIZE_GARBAGE_ASSIGN"))
+ emit(Seq("`define RANDOMIZE"))
+ emit(Seq("`endif"))
+ emit(Seq("`ifdef RANDOMIZE_INVALID_ASSIGN"))
+ emit(Seq("`define RANDOMIZE"))
+ emit(Seq("`endif"))
+ emit(Seq("`ifdef RANDOMIZE_REG_INIT"))
+ emit(Seq("`define RANDOMIZE"))
+ emit(Seq("`endif"))
+ emit(Seq("`ifdef RANDOMIZE_MEM_INIT"))
+ emit(Seq("`define RANDOMIZE"))
+ emit(Seq("`endif"))
+ emit(Seq("`ifndef RANDOM"))
+ emit(Seq("`define RANDOM $random"))
+ emit(Seq("`endif"))
+ // the initvar is also used to initialize memories to constants
+ if (memoryInitials.isEmpty) emit(Seq("`ifdef RANDOMIZE_MEM_INIT"))
+ // Since simulators don't actually support memories larger than 2^31 - 1, there is no reason
+ // to change Verilog emission in the common case. Instead, we only emit a larger initvar
+ // where necessary
+ if (maxMemSize.isValidInt) {
+ emit(Seq(" integer initvar;"))
+ } else {
+ // Width must be able to represent maxMemSize because that's the upper bound in init loop
+ val width = maxMemSize.bitLength - 1 // minus one because [width-1:0] has a width of "width"
+ emit(Seq(s" reg [$width:0] initvar;"))
+ }
+ if (memoryInitials.isEmpty) emit(Seq("`endif"))
+ emit(Seq("`ifndef SYNTHESIS"))
+ // User-defined macro of code to run before an initial block
+ emit(Seq("`ifdef FIRRTL_BEFORE_INITIAL"))
+ emit(Seq("`FIRRTL_BEFORE_INITIAL"))
+ emit(Seq("`endif"))
+ emit(Seq("initial begin"))
+ emit(Seq(" `ifdef RANDOMIZE"))
+ emit(Seq(" `ifdef INIT_RANDOM"))
+ emit(Seq(" `INIT_RANDOM"))
+ emit(Seq(" `endif"))
+ // This enables testbenches to seed the random values at some time
+ // before `RANDOMIZE_DELAY (or the legacy value 0.002 if
+ // `RANDOMIZE_DELAY is not defined).
+ // Verilator does not support delay statements, so they are omitted.
+ emit(Seq(" `ifndef VERILATOR"))
+ emit(Seq(" `ifdef RANDOMIZE_DELAY"))
+ emit(Seq(" #`RANDOMIZE_DELAY begin end"))
+ emit(Seq(" `else"))
+ emit(Seq(" #0.002 begin end"))
+ emit(Seq(" `endif"))
+ emit(Seq(" `endif"))
+ ifdefInitials.toSeq.sortWith(_._1 < _._1).foreach {
+ case (ifdef, initials) =>
+ emit(Seq("`ifdef " + ifdef))
+ for (x <- initials) emit(Seq(tab, x))
+ emit(Seq("`endif // " + ifdef))
+ }
+ for (x <- initials) emit(Seq(tab, x))
+ for (x <- asyncInitials) emit(Seq(tab, x))
+ emit(Seq(" `endif // RANDOMIZE"))
+ for (x <- memoryInitials) emit(Seq(tab, x))
+ emit(Seq("end // initial"))
+ // User-defined macro of code to run after an initial block
+ emit(Seq("`ifdef FIRRTL_AFTER_INITIAL"))
+ emit(Seq("`FIRRTL_AFTER_INITIAL"))
+ emit(Seq("`endif"))
+ emit(Seq("`endif // SYNTHESIS"))
+ }
+
+ if (formals.keys.nonEmpty) {
+ for ((clk, content) <- formals if content.nonEmpty) {
+ emit(Seq(tab, "always @(posedge ", clk, ") begin"))
+ for (line <- content) emit(Seq(tab, tab, line))
+ emit(Seq(tab, "end"))
+ }
+ }
+
+ emit(Seq("endmodule"))
+ }
+
+ /**
+ * The standard verilog emitter, wraps up everything into the
+ * verilog
+ * @return
+ */
+ def emit_verilog(): DefModule = {
+
+ build_netlist(m.body)
+ build_ports()
+ build_streams(m.body)
+ emit_streams()
+ m
+ }
+
+ /**
+ * This emits a verilog module that can be bound to a module defined in chisel.
+ * It uses the same machinery as the general emitter in order to insure that
+ * parameters signature is exactly the same as the module being bound to
+ * @param overrideName Override the module name
+ * @param body the body of the bind module
+ * @return A module constructed from the body
+ */
+ def emitVerilogBind(overrideName: String, body: String): DefModule = {
+ build_netlist(m.body)
+ build_ports()
+
+ build_description(description).foreach(emit(_))
+
+ emit(Seq("module ", overrideName, "(", m.info))
+ for (x <- portdefs) emit(Seq(tab, x))
+
+ emit(Seq(");"))
+ emit(body)
+ emit(Seq("endmodule"), top = 0)
+ m
+ }
+ }
+
+ /** Preamble for every emitted Verilog file */
+ def transforms = new TransformManager(firrtl.stage.Forms.VerilogOptimized, prerequisites).flattenedTransformOrder
+
+ def emit(state: CircuitState, writer: Writer): Unit = {
+ val cs = runTransforms(state)
+ val emissionOptions = new EmissionOptions(cs.annotations)
+ val moduleMap = cs.circuit.modules.map(m => m.name -> m).toMap
+ cs.circuit.modules.foreach {
+ case dm @ DescribedMod(d, pds, m: Module) =>
+ val renderer = new VerilogRender(d, pds, m, moduleMap, cs.circuit.main, emissionOptions)(writer)
+ renderer.emit_verilog()
+ case m: Module =>
+ val renderer = new VerilogRender(m, moduleMap, cs.circuit.main, emissionOptions)(writer)
+ renderer.emit_verilog()
+ case _ => // do nothing
+ }
+ }
+
+ override def execute(state: CircuitState): CircuitState = {
+ val writerToString =
+ (writer: java.io.StringWriter) => writer.toString.replaceAll("""(?m) +$""", "") // trim trailing whitespace
+
+ val newAnnos = state.annotations.flatMap {
+ case EmitCircuitAnnotation(a) if this.getClass == a =>
+ val writer = new java.io.StringWriter
+ emit(state, writer)
+ Seq(
+ EmittedVerilogCircuitAnnotation(
+ EmittedVerilogCircuit(state.circuit.main, writerToString(writer), outputSuffix)
+ )
+ )
+
+ case EmitAllModulesAnnotation(a) if this.getClass == a =>
+ val cs = runTransforms(state)
+ val emissionOptions = new EmissionOptions(cs.annotations)
+ val moduleMap = cs.circuit.modules.map(m => m.name -> m).toMap
+
+ cs.circuit.modules.flatMap {
+ case dm @ DescribedMod(d, pds, module: Module) =>
+ val writer = new java.io.StringWriter
+ val renderer = new VerilogRender(d, pds, module, moduleMap, cs.circuit.main, emissionOptions)(writer)
+ renderer.emit_verilog()
+ Some(
+ EmittedVerilogModuleAnnotation(EmittedVerilogModule(module.name, writerToString(writer), outputSuffix))
+ )
+ case module: Module =>
+ val writer = new java.io.StringWriter
+ val renderer = new VerilogRender(module, moduleMap, cs.circuit.main, emissionOptions)(writer)
+ renderer.emit_verilog()
+ Some(
+ EmittedVerilogModuleAnnotation(EmittedVerilogModule(module.name, writerToString(writer), outputSuffix))
+ )
+ case _ => None
+ }
+ case _ => Seq()
+ }
+ state.copy(annotations = newAnnos ++ state.annotations)
+ }
+}
+
+case class VRandom(width: BigInt) extends Expression {
+ def tpe = UIntType(IntWidth(width))
+ def nWords = (width + 31) / 32
+ def realWidth = nWords * 32
+ override def serialize: String = "RANDOM"
+ def mapExpr(f: Expression => Expression): Expression = this
+ def mapType(f: Type => Type): Expression = this
+ def mapWidth(f: Width => Width): Expression = this
+ def foreachExpr(f: Expression => Unit): Unit = ()
+ def foreachType(f: Type => Unit): Unit = ()
+ def foreachWidth(f: Width => Unit): Unit = ()
+}
diff --git a/src/main/scala/firrtl/package.scala b/src/main/scala/firrtl/package.scala
index 999b123d..adaddeda 100644
--- a/src/main/scala/firrtl/package.scala
+++ b/src/main/scala/firrtl/package.scala
@@ -10,10 +10,10 @@ package object firrtl {
implicit def annoSeqToSeq(as: AnnotationSeq): Seq[Annotation] = as.underlying
/* Options as annotations compatibility items */
- @deprecated("Use firrtl.stage.TargetDirAnnotation", "1.2")
+ @deprecated("Use firrtl.stage.TargetDirAnnotation", "FIRRTL 1.2")
type TargetDirAnnotation = firrtl.options.TargetDirAnnotation
- @deprecated("Use firrtl.stage.TargetDirAnnotation", "1.2")
+ @deprecated("Use firrtl.stage.TargetDirAnnotation", "FIRRTL 1.2")
val TargetDirAnnotation = firrtl.options.TargetDirAnnotation
type WRef = ir.Reference
diff --git a/src/main/scala/firrtl/passes/InferTypes.scala b/src/main/scala/firrtl/passes/InferTypes.scala
index bbc1ef6d..01f0b823 100644
--- a/src/main/scala/firrtl/passes/InferTypes.scala
+++ b/src/main/scala/firrtl/passes/InferTypes.scala
@@ -13,7 +13,7 @@ object InferTypes extends Pass {
override def prerequisites = Dependency(ResolveKinds) +: firrtl.stage.Forms.WorkingIR
override def invalidates(a: Transform) = false
- @deprecated("This should never have been public", "1.3.2")
+ @deprecated("This should never have been public", "FIRRTL 1.3.2")
type TypeMap = collection.mutable.LinkedHashMap[String, Type]
private type TypeLookup = collection.mutable.HashMap[String, Type]
@@ -102,7 +102,7 @@ object CInferTypes extends Pass {
override def prerequisites = firrtl.stage.Forms.ChirrtlForm
override def invalidates(a: Transform) = false
- @deprecated("This should never have been public", "1.3.2")
+ @deprecated("This should never have been public", "FIRRTL 1.3.2")
type TypeMap = collection.mutable.LinkedHashMap[String, Type]
private type TypeLookup = collection.mutable.HashMap[String, Type]
diff --git a/src/main/scala/firrtl/passes/wiring/WiringUtils.scala b/src/main/scala/firrtl/passes/wiring/WiringUtils.scala
index 0b121cc0..d926f6a9 100644
--- a/src/main/scala/firrtl/passes/wiring/WiringUtils.scala
+++ b/src/main/scala/firrtl/passes/wiring/WiringUtils.scala
@@ -37,7 +37,7 @@ case class Modifications(
/** A lineage tree representing the instance hierarchy in a design
*/
-@deprecated("Use DiGraph/InstanceGraph", "1.1.1")
+@deprecated("Use DiGraph/InstanceGraph", "FIRRTL 1.1.1")
case class Lineage(
name: String,
children: Seq[(String, Lineage)] = Seq.empty,
@@ -80,13 +80,13 @@ case class Lineage(
}
object WiringUtils {
- @deprecated("Use DiGraph/InstanceGraph", "1.1.1")
+ @deprecated("Use DiGraph/InstanceGraph", "FIRRTL 1.1.1")
type ChildrenMap = mutable.HashMap[String, Seq[(String, String)]]
/** Given a circuit, returns a map from module name to children
* instance/module names
*/
- @deprecated("Use DiGraph/InstanceGraph", "1.1.1")
+ @deprecated("Use DiGraph/InstanceGraph", "FIRRTL 1.1.1")
def getChildrenMap(c: Circuit): ChildrenMap = {
val childrenMap = new ChildrenMap()
def getChildren(mname: String)(s: Statement): Unit = s match {
@@ -105,7 +105,7 @@ object WiringUtils {
/** Returns a module's lineage, containing all children lineages as well
*/
- @deprecated("Use DiGraph/InstanceGraph", "1.1.1")
+ @deprecated("Use DiGraph/InstanceGraph", "FIRRTL 1.1.1")
def getLineage(childrenMap: ChildrenMap, module: String): Lineage =
Lineage(module, childrenMap(module).map { case (i, m) => (i, getLineage(childrenMap, m)) })
diff --git a/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala b/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala
index 12f33183..d1c0a134 100644
--- a/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala
+++ b/src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala
@@ -182,7 +182,10 @@ object BlackBoxSourceHelper {
val defaultFileListName = "firrtl_black_box_resource_files.f"
- @deprecated("Renamed to defaultFileListName, as the file list name may now be changed with an annotation", "1.2")
+ @deprecated(
+ "Renamed to defaultFileListName, as the file list name may now be changed with an annotation",
+ "FIRRTL 1.2"
+ )
def fileListName = defaultFileListName
def writeTextToFile(text: String, file: File): Unit = {
diff --git a/src/main/scala/firrtl/transforms/InferResets.scala b/src/main/scala/firrtl/transforms/InferResets.scala
index 0f5fb608..4c6ffde2 100644
--- a/src/main/scala/firrtl/transforms/InferResets.scala
+++ b/src/main/scala/firrtl/transforms/InferResets.scala
@@ -16,9 +16,9 @@ import scala.collection.mutable
import scala.util.Try
object InferResets {
- @deprecated("This is no longer in use and will be removed", "1.3")
+ @deprecated("This is no longer in use and will be removed", "FIRRTL 1.3")
final class DifferingDriverTypesException private (msg: String) extends PassException(msg)
- @deprecated("This is no longer in use and will be removed", "1.3")
+ @deprecated("This is no longer in use and will be removed", "FIRRTL 1.3")
object DifferingDriverTypesException {
def apply(target: ReferenceTarget, tpes: Seq[(Type, Seq[TypeDriver])]): DifferingDriverTypesException = {
val xs = tpes.map { case (t, ds) => s"${ds.map(_.target().serialize).mkString(", ")} of type ${t.serialize}" }
diff --git a/src/main/scala/firrtl/util/BackendCompilationUtilities.scala b/src/main/scala/firrtl/util/BackendCompilationUtilities.scala
index 8d2d8be9..7d5fec1d 100644
--- a/src/main/scala/firrtl/util/BackendCompilationUtilities.scala
+++ b/src/main/scala/firrtl/util/BackendCompilationUtilities.scala
@@ -247,7 +247,7 @@ object BackendCompilationUtilities extends LazyLogging {
}
}
-@deprecated("use object BackendCompilationUtilities", "1.3")
+@deprecated("use object BackendCompilationUtilities", "FIRRTL 1.3")
trait BackendCompilationUtilities extends LazyLogging {
lazy val TestDirectory = BackendCompilationUtilities.TestDirectory
def timeStamp: String = BackendCompilationUtilities.timeStamp
diff --git a/src/main/scala/logger/Logger.scala b/src/main/scala/logger/Logger.scala
index fe4b8111..80c024fb 100644
--- a/src/main/scala/logger/Logger.scala
+++ b/src/main/scala/logger/Logger.scala
@@ -122,7 +122,7 @@ object Logger {
* @tparam A The return type of codeBlock
* @return Whatever block returns
*/
- @deprecated("Use makeScope(opts: FirrtlOptions)", "1.2")
+ @deprecated("Use makeScope(opts: FirrtlOptions)", "FIRRTL 1.2")
def makeScope[A](manager: ExecutionOptionsManager)(codeBlock: => A): A =
makeScope(manager.commonOptions.toAnnotations)(codeBlock)
@@ -134,7 +134,7 @@ object Logger {
* @tparam A return type of codeBlock
* @return
*/
- @deprecated("Use makescope(opts: FirrtlOptions)", "1.2")
+ @deprecated("Use makescope(opts: FirrtlOptions)", "FIRRTL 1.2")
def makeScope[A](args: Array[String] = Array.empty)(codeBlock: => A): A = {
val executionOptionsManager = new ExecutionOptionsManager("logger")
if (executionOptionsManager.parse(args)) {
@@ -353,7 +353,7 @@ object Logger {
* from the command line via an options manager
* @param optionsManager manager
*/
- @deprecated("Use setOptions(annotations: AnnotationSeq)", "1.2")
+ @deprecated("Use setOptions(annotations: AnnotationSeq)", "FIRRTL 1.2")
def setOptions(optionsManager: ExecutionOptionsManager): Unit =
setOptions(optionsManager.commonOptions.toAnnotations)
diff --git a/src/main/scala/logger/LoggerOptions.scala b/src/main/scala/logger/LoggerOptions.scala
index c0b5d35c..683d6741 100644
--- a/src/main/scala/logger/LoggerOptions.scala
+++ b/src/main/scala/logger/LoggerOptions.scala
@@ -35,6 +35,6 @@ class LoggerOptions private[logger] (
def getLogFileName(): Option[String] = if (!logToFile) None else logFileName.orElse(Some("a.log"))
/** True if a [[Logger]] should be writing to a file */
- @deprecated("logToFile was removed, use logFileName.nonEmpty", "1.2")
+ @deprecated("logToFile was removed, use logFileName.nonEmpty", "FIRRTL 1.2")
def logToFile(): Boolean = logFileName.nonEmpty
}