diff options
Diffstat (limited to 'src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala')
| -rw-r--r-- | src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala | 1319 |
1 files changed, 1319 insertions, 0 deletions
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 = () +} |
