diff --git a/.gitignore b/.gitignore index 8b3d51a642..dd2f998ba5 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ project/metals.sbt *~ *#*# +.vscode diff --git a/src/main/scala/firrtl/EmissionOption.scala b/src/main/scala/firrtl/EmissionOption.scala index 074d9c2886..90eb585186 100644 --- a/src/main/scala/firrtl/EmissionOption.scala +++ b/src/main/scala/firrtl/EmissionOption.scala @@ -2,6 +2,8 @@ package firrtl +import firrtl.annotations.MemoryLoadFileType + /** * Base type for emission customization options * NOTE: all the following traits must be mixed with SingleTargetAnnotation[T <: Named] @@ -18,6 +20,7 @@ sealed trait MemoryInitValue case object MemoryRandomInit extends MemoryInitValue case class MemoryScalarInit(value: BigInt) extends MemoryInitValue case class MemoryArrayInit(values: Seq[BigInt]) extends MemoryInitValue +case class MemoryFileInlineInit(filename: String, hexOrBinary: MemoryLoadFileType.FileType) extends MemoryInitValue /** default Emitter behavior for memories */ case object MemoryEmissionOptionDefault extends MemoryEmissionOption diff --git a/src/main/scala/firrtl/annotations/MemoryInitAnnotation.scala b/src/main/scala/firrtl/annotations/MemoryInitAnnotation.scala index 44656e0d08..62dc96f485 100644 --- a/src/main/scala/firrtl/annotations/MemoryInitAnnotation.scala +++ b/src/main/scala/firrtl/annotations/MemoryInitAnnotation.scala @@ -2,7 +2,14 @@ package firrtl.annotations -import firrtl.{MemoryArrayInit, MemoryEmissionOption, MemoryInitValue, MemoryRandomInit, MemoryScalarInit} +import firrtl.{ + MemoryArrayInit, + MemoryEmissionOption, + MemoryFileInlineInit, + MemoryInitValue, + MemoryRandomInit, + MemoryScalarInit +} /** * Represents the initial value of the annotated memory. @@ -33,3 +40,15 @@ case class MemoryArrayInitAnnotation(target: ReferenceTarget, values: Seq[BigInt override def initValue: MemoryInitValue = MemoryArrayInit(values) override def isRandomInit: Boolean = false } + +/** Initialize the `target` memory with inline readmem[hb] statement. */ +case class MemoryFileInlineAnnotation( + target: ReferenceTarget, + filename: String, + hexOrBinary: MemoryLoadFileType.FileType = MemoryLoadFileType.Hex) + extends MemoryInitAnnotation { + require(filename.trim.nonEmpty, "empty filename not allowed in MemoryFileInlineAnnotation") + override def duplicate(n: ReferenceTarget): Annotation = copy(n) + override def initValue: MemoryInitValue = MemoryFileInlineInit(filename, hexOrBinary) + override def isRandomInit: Boolean = false +} diff --git a/src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala b/src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala index f1650ad741..bc4996df42 100644 --- a/src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala +++ b/src/main/scala/firrtl/backends/verilog/VerilogEmitter.scala @@ -7,7 +7,7 @@ import firrtl.PrimOps._ import firrtl.Utils._ import firrtl.WrappedExpression._ import firrtl.traversals.Foreachers._ -import firrtl.annotations.{CircuitTarget, ReferenceTarget, SingleTargetAnnotation} +import firrtl.annotations.{CircuitTarget, MemoryLoadFileType, ReferenceTarget, SingleTargetAnnotation} import firrtl.passes.LowerTypes import firrtl.passes.MemPortUtils._ import firrtl.stage.TransformManager @@ -849,6 +849,16 @@ class VerilogEmitter extends SeqTransform with Emitter { rstring, ";" ) + case MemoryFileInlineInit(filename, hexOrBinary) => + val readmem = hexOrBinary match { + case MemoryLoadFileType.Binary => "$readmemb" + case MemoryLoadFileType.Hex => "$readmemh" + } + val inlineLoad = s""" + |initial begin + | $readmem("$filename", ${s.name}); + |end""".stripMargin + memoryInitials += Seq(inlineLoad) } } diff --git a/src/test/scala/firrtlTests/MemoryInitSpec.scala b/src/test/scala/firrtlTests/MemoryInitSpec.scala index 18f2b7ffda..a7c9966a3e 100644 --- a/src/test/scala/firrtlTests/MemoryInitSpec.scala +++ b/src/test/scala/firrtlTests/MemoryInitSpec.scala @@ -165,6 +165,23 @@ class MemInitSpec extends FirrtlFlatSpec { assert(annos == Seq(MemoryArrayInitAnnotation(mRef, largeSeq))) } + "MemoryFileInlineAnnotation" should "emit $readmemh for text.hex" in { + val annos = Seq(MemoryFileInlineAnnotation(mRef, filename = "text.hex")) + val result = compile(annos) + result should containLine("""$readmemh("text.hex", """ + mRef.name + """);""") + } + + "MemoryFileInlineAnnotation" should "emit $readmemb for text.bin" in { + val annos = Seq(MemoryFileInlineAnnotation(mRef, filename = "text.bin", hexOrBinary = MemoryLoadFileType.Binary)) + val result = compile(annos) + result should containLine("""$readmemb("text.bin", """ + mRef.name + """);""") + } + + "MemoryFileInlineAnnotation" should "fail with blank filename" in { + assertThrows[Exception] { + compile(Seq(MemoryFileInlineAnnotation(mRef, filename = ""))) + } + } } abstract class MemInitExecutionSpec(values: Seq[Int], init: ReferenceTarget => Annotation)