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.{ Annotation, CircuitTarget, MemoryInitAnnotation, MemoryLoadFileType, MemoryNoSynthInit, MemorySynthInit, 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) } /** Identifies PrimOps that never need parentheses * * These PrimOps emit either {..., a0, ...} or a0 so they never need parentheses */ private val neverParens: PrimOp => Boolean = Set(Shl, Cat, Cvt, AsUInt, AsSInt, AsClock, AsAsyncReset, Pad) } 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 { case op if neverParens(op) => 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 = neverParens(e.op) || 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]( annotations.collectFirst { case a: CustomDefaultMemoryEmission => a }.getOrElse(MemoryEmissionOptionDefault) ) private val registerEmissionOption = new EmissionOptionMap[RegisterEmissionOption]( annotations.collectFirst { case a: CustomDefaultRegisterEmission => a }.getOrElse(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) // Defines the memory initialization based on the annotation // Defaults to having the memories inside the `ifndef SYNTHESIS` block def emitMemoryInitAsNoSynth: Boolean = { val annos = annotations.collect { case a @ (MemoryNoSynthInit | MemorySynthInit) => a } annos match { case Seq() => true case Seq(MemoryNoSynthInit) => true case Seq(MemorySynthInit) => false case other => throw new FirrtlUserException( "There should only be at most one memory initialization option annotation, got $other" ) } } private val emissionAnnos = annotations.collect { case m: SingleTargetAnnotation[ReferenceTarget] @unchecked with EmissionOption => m } annotations.foreach { case a: Annotation if a.dedup.nonEmpty => val (_, _, target) = a.dedup.get if (!target.isLocal) { throw new FirrtlUserException( s"At least one dedupable annotation did not deduplicate: got non-local annotation $a from [[DedupAnnotationsTransform]]" ) } case _ => } // 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(info, fv) = netlist(r) asyncResetAlwaysBlocks += ( ( clk, reset, addUpdate(info, 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, ";" ) case MemoryFileInlineInit(filename, hexOrBinary) => val readmem = hexOrBinary match { case MemoryLoadFileType.Binary => "$readmemb" case MemoryLoadFileType.Hex => "$readmemh" } memoryInitials += Seq(s"""$readmem("$filename", ${s.name});""") case MemoryNoInit => // do nothing } } 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) // Currently, no idiomatic way to directly emit write-first RW ports val hasComplexRW = (sx.readwriters.nonEmpty && (sx.readLatency != 1 || sx.readUnderWrite == ReadUnderWrite.New)) if (sx.readLatency > 1 || sx.writeLatency != 1 || hasComplexRW) throw EmitterException( Seq( s"Memory ${sx.name} is too complex to emit directly.", "Consider running VerilogMemDelays to simplify complex memories.", "Alternatively, add the --repl-seq-mem flag to replace memories with blackboxes." ).mkString(" ") ) def createMemWire(firrtlRef: Expression, rhs: InfoExpr): Unit = { // Don't use declaration-assignment, since this assignment might be emitted earlier than the // actual connection to the memory port field in the source FIRRTL declare("wire", LowerTypes.loweredName(firrtlRef), firrtlRef.tpe, MultiInfo(sx.info, rhs.info)) assign(firrtlRef, rhs) } for (r <- sx.readers) { val data = memPortField(sx, r, "data") val addr = memPortField(sx, r, "addr") val en = memPortField(sx, r, "en") val memPort = WSubAccess(WRef(sx), addr, sx.dataType, UnknownFlow) val depthValue = UIntLiteral(sx.depth, IntWidth(sx.depth.bitLength)) val garbageGuard = DoPrim(Geq, Seq(addr, depthValue), Seq(), UnknownType) val clkSource = netlist(memPortField(sx, r, "clk")).expr createMemWire(en, netlist(en)) if (sx.readLatency == 1 && sx.readUnderWrite != ReadUnderWrite.Old) { val InfoExpr(addrInfo, addrDriver) = netlist(addr) declare("reg", LowerTypes.loweredName(addr), addr.tpe, sx.info) initialize(WRef(LowerTypes.loweredName(addr), addr.tpe), zero, zero) update(addr, addrDriver, clkSource, en, addrInfo) } else { createMemWire(addr, netlist(addr)) } if (sx.readLatency == 1 && sx.readUnderWrite == ReadUnderWrite.Old) { declare("reg", LowerTypes.loweredName(data), data.tpe, sx.info) initialize(WRef(LowerTypes.loweredName(data), data.tpe), zero, zero) update(data, memPort, clkSource, en, sx.info) } else { declare("wire", LowerTypes.loweredName(data), data.tpe, sx.info) 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") val clkSource = netlist(memPortField(sx, w, "clk")).expr createMemWire(data, netlist(data)) createMemWire(addr, netlist(addr)) createMemWire(mask, netlist(mask)) createMemWire(en, netlist(en)) val memPort = WSubAccess(WRef(sx), addr, sx.dataType, UnknownFlow) update(memPort, data, clkSource, AND(en, mask), sx.info) } for (rw <- sx.readwriters) { val rdata = memPortField(sx, rw, "rdata") val wdata = memPortField(sx, rw, "wdata") val addr = memPortField(sx, rw, "addr") val en = memPortField(sx, rw, "en") val wmode = memPortField(sx, rw, "wmode") val wmask = memPortField(sx, rw, "wmask") val memPort = WSubAccess(WRef(sx), addr, sx.dataType, UnknownFlow) val clkSource = netlist(memPortField(sx, rw, "clk")).expr createMemWire(wdata, netlist(wdata)) createMemWire(addr, netlist(addr)) createMemWire(wmode, netlist(wmode)) createMemWire(wmask, netlist(wmask)) createMemWire(en, netlist(en)) declare("reg", LowerTypes.loweredName(rdata), rdata.tpe, sx.info) initialize(WRef(LowerTypes.loweredName(rdata), rdata.tpe), zero, zero) update(rdata, memPort, clkSource, en, sx.info) update(memPort, wdata, clkSource, AND(en, AND(wmode, wmask)), sx.info) } 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")) if (emissionOptions.emitMemoryInitAsNoSynth) { 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 (!emissionOptions.emitMemoryInitAsNoSynth && !memoryInitials.isEmpty) { emit(Seq("initial begin")) for (x <- memoryInitials) emit(Seq(tab, x)) emit(Seq("end")) } } 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 = () }