diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000000..33ff998e92c
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @freechipsproject/chisel-reviewers
diff --git a/README.md b/README.md
index ccf797ba699..15104e29c0e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
-# Chisel 3
+
+
+#
[](https://gitter.im/freechipsproject/chisel3?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -164,11 +166,9 @@ sbt test
```
### Running Projects Against Local Chisel
-Chisel3 is still undergoing rapid development and we haven't pusblished a
-stable version to the Nexus repository.
-You will need to build from source and `publishLocal`.
+To use the development version of Chisel (`master` branch), you will need to build from source and `publishLocal`.
The repo version can be found in the build.sbt file.
-At last check it was:
+As of the time of writing it was:
version := "3.2-SNAPSHOT",
diff --git a/build.sbt b/build.sbt
index d828391178d..9180f5fc8b2 100644
--- a/build.sbt
+++ b/build.sbt
@@ -100,7 +100,7 @@ lazy val chiselSettings = Seq (
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.1" % "test",
"org.scalacheck" %% "scalacheck" % "1.13.4" % "test",
- "com.github.scopt" %% "scopt" % "3.6.0"
+ "com.github.scopt" %% "scopt" % "3.7.0"
),
// Tests from other projects may still run concurrently.
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 53e34312027..a36dfe1ff66 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -232,7 +232,7 @@ sealed class Vec[T <: Data] private[core] (gen: => T, val length: Int)
def apply(idx: Int): T = self(idx)
override def cloneType: this.type = {
- new Vec(gen.cloneType, length).asInstanceOf[this.type]
+ new Vec(gen.cloneTypeFull, length).asInstanceOf[this.type]
}
override def getElements: Seq[Data] =
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
index 910f1e19930..e52be8042b5 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
@@ -141,7 +141,13 @@ abstract class BaseModule extends HasId {
def desiredName = this.getClass.getName.split('.').last
/** Legalized name of this module. */
- final val name = Builder.globalNamespace.name(desiredName)
+ final lazy val name = try {
+ Builder.globalNamespace.name(desiredName)
+ } catch {
+ case e: NullPointerException => throwException(
+ s"Error: desiredName of ${this.getClass.getName} is null. Did you evaluate 'name' before all values needed by desiredName were available?", e)
+ case t: Throwable => throw t
+ }
/** Returns a FIRRTL ModuleName that references this object
* @note Should not be called until circuit elaboration is complete
diff --git a/doc/images/chisel_logo.png b/doc/images/chisel_logo.png
new file mode 100644
index 00000000000..df7d0001fb8
Binary files /dev/null and b/doc/images/chisel_logo.png differ
diff --git a/doc/images/chisel_logo.svg b/doc/images/chisel_logo.svg
new file mode 100644
index 00000000000..a6b1e27386e
--- /dev/null
+++ b/doc/images/chisel_logo.svg
@@ -0,0 +1,12593 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala
index 25d254256e0..f1bb8d888a9 100644
--- a/src/main/scala/chisel3/Driver.scala
+++ b/src/main/scala/chisel3/Driver.scala
@@ -68,7 +68,7 @@ trait ChiselExecutionResult
*
* @param circuitOption Optional circuit, has information like circuit name
* @param emitted The emitted Chirrrl text
- * @param firrtlResultOption Optional Firrtl result, @see ucb-bar/firrtl for details
+ * @param firrtlResultOption Optional Firrtl result, @see freechipsproject/firrtl for details
*/
case class ChiselExecutionSuccess(
circuitOption: Option[Circuit],
@@ -77,9 +77,9 @@ case class ChiselExecutionSuccess(
) extends ChiselExecutionResult
/**
- * Getting one of these indicates failure of some sort
- *
- * @param message a clue perhaps will be provided in the here
+ * Getting one of these indicates failure of some sort.
+ *
+ * @param message A clue might be provided here.
*/
case class ChiselExecutionFailure(message: String) extends ChiselExecutionResult
diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala
index 6b96f67068d..4c3f8197d6f 100644
--- a/src/main/scala/chisel3/package.scala
+++ b/src/main/scala/chisel3/package.scala
@@ -245,6 +245,8 @@ package object chisel3 { // scalastyle:ignore package.object.name
type BlackBox = chisel3.core.BlackBox
+ type InstanceId = chisel3.internal.InstanceId
+
val Mem = chisel3.core.Mem
type MemBase[T <: Data] = chisel3.core.MemBase[T]
type Mem[T <: Data] = chisel3.core.Mem[T]
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index 89ad3115738..d2a6552d54a 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -6,7 +6,7 @@
package chisel3.util
import chisel3._
-import chisel3.experimental.{DataMirror, Direction}
+import chisel3.experimental.{DataMirror, Direction, requireIsChiselType}
import chisel3.internal.naming._ // can't use chisel3_ version because of compile order
/** An I/O Bundle containing 'valid' and 'ready' signals that handshake
@@ -36,7 +36,7 @@ object ReadyValidIO {
implicit class AddMethodsToReadyValid[T<:Data](target: ReadyValidIO[T]) {
def fire(): Bool = target.ready && target.valid
- /** push dat onto the output bits of this interface to let the consumer know it has happened.
+ /** Push dat onto the output bits of this interface to let the consumer know it has happened.
* @param dat the values to assign to bits.
* @return dat.
*/
@@ -47,22 +47,23 @@ object ReadyValidIO {
}
/** Indicate no enqueue occurs. Valid is set to false, and bits are
- * connected to an uninitialized wire
+ * connected to an uninitialized wire.
*/
def noenq(): Unit = {
target.valid := false.B
+ target.bits := DontCare
}
/** Assert ready on this port and return the associated data bits.
* This is typically used when valid has been asserted by the producer side.
- * @return the data for this device,
+ * @return The data bits.
*/
def deq(): T = {
target.ready := true.B
target.bits
}
- /** Indicate no dequeue occurs. Ready is set to false
+ /** Indicate no dequeue occurs. Ready is set to false.
*/
def nodeq(): Unit = {
target.ready := false.B
@@ -199,7 +200,7 @@ class Queue[T <: Data](gen: T,
}
val genType = if (compileOptions.declaredTypeMustBeUnbound) {
- experimental.requireIsChiselType(gen)
+ requireIsChiselType(gen)
gen
} else {
if (DataMirror.internal.isSynthesizable(gen)) {
@@ -252,7 +253,7 @@ class Queue[T <: Data](gen: T,
private val ptr_diff = enq_ptr.value - deq_ptr.value
if (isPow2(entries)) {
- io.count := Cat(maybe_full && ptr_match, ptr_diff)
+ io.count := Mux(maybe_full && ptr_match, entries.U, 0.U) | ptr_diff
} else {
io.count := Mux(ptr_match,
Mux(maybe_full,
diff --git a/src/main/scala/chisel3/util/experimental/LoadMemoryTransform.scala b/src/main/scala/chisel3/util/experimental/LoadMemoryTransform.scala
new file mode 100644
index 00000000000..04a01fe9a88
--- /dev/null
+++ b/src/main/scala/chisel3/util/experimental/LoadMemoryTransform.scala
@@ -0,0 +1,234 @@
+// See LICENSE for license details.
+
+package chisel3.util.experimental
+
+import chisel3._
+import chisel3.experimental.annotate
+// import chisel3.InstanceId
+import chisel3.experimental.{ChiselAnnotation, RunFirrtlTransform}
+import firrtl.annotations.{MemoryLoadFileType, _}
+import firrtl.ir.{Module => _, _}
+import firrtl.transforms.BlackBoxInlineAnno
+import firrtl.Mappers._
+import firrtl.{AnnotationSeq, CircuitForm, CircuitState, EmitCircuitAnnotation, LowForm, Transform, VerilogEmitter}
+
+import scala.collection.mutable
+
+/** This is the annotation created when using [[loadMemoryFromFile]], it records the memory, the load file
+ * and the format of the file.
+ * @param target memory to load
+ * @param fileName name of input file
+ * @param hexOrBinary use $readmemh or $readmemb, i.e. hex or binary text input, default is hex
+ */
+case class ChiselLoadMemoryAnnotation[T <: Data](
+ target: MemBase[T],
+ fileName: String,
+ hexOrBinary: MemoryLoadFileType.FileType = MemoryLoadFileType.Hex
+)
+ extends ChiselAnnotation with RunFirrtlTransform {
+
+ if(fileName.isEmpty) {
+ throw new Exception(
+ s"""LoadMemory from file annotations file empty file name"""
+ )
+ }
+
+ def transformClass: Class[LoadMemoryTransform] = classOf[LoadMemoryTransform]
+
+ def toFirrtl: LoadMemoryAnnotation = {
+ LoadMemoryAnnotation(target.toNamed.asInstanceOf[ComponentName], fileName, hexOrBinary)
+ }
+}
+
+
+object loadMemoryFromFile {
+ /** Use this annotation generator to load a memory from a text file by using verilator and
+ * verilog's $readmemh or $readmemb.
+ * The treadle backend can also recognize this annotation and load memory at run-time.
+ *
+ * This annotation triggers the [[LoadMemoryTransform]] which will take add the verilog directive to
+ * the relevant module by using the creating separate modules that are bound to the modules containing
+ * the memories to be loaded.
+ *
+ * ==Example module==
+ *
+ * Consider a simple Module containing a memory
+ * {{{
+ * import chisel3._
+ * class UsesMem(memoryDepth: Int, memoryType: Data) extends Module {
+ * val io = IO(new Bundle {
+ * val address = Input(UInt(memoryType.getWidth.W))
+ * val value = Output(memoryType)
+ * })
+ * val memory = Mem(memoryDepth, memoryType)
+ * io.value := memory(io.address)
+ * }
+ * }}}
+ *
+ * ==Above module with annotation==
+ *
+ * To load this memory from a file /workspace/workdir/mem1.hex.txt
+ * Just add an import and annotate the memory
+ * {{{
+ * import chisel3._
+ * import chisel3.util.experimental.loadMemoryFromFile // <<-- new import here
+ * class UsesMem(memoryDepth: Int, memoryType: Data) extends Module {
+ * val io = IO(new Bundle {
+ * val address = Input(UInt(memoryType.getWidth.W))
+ * val value = Output(memoryType)
+ * })
+ * val memory = Mem(memoryDepth, memoryType)
+ * io.value := memory(io.address)
+ * loadMemoryFromFile(memory, "/workspace/workdir/mem1.hex.txt") // <<-- Note the annotation here
+ * }
+ * }}}
+ *
+ * ==Example file format==
+ * A memory file should consist of ascii text in either hex or binary format
+ * Example (a file containing the decimal values 0, 7, 14, 21):
+ * {{{
+ * 0
+ * 7
+ * d
+ * 15
+ * }}}
+ * Binary file is similarly constructed.
+ *
+ * ==More info==
+ * See the LoadMemoryFromFileSpec.scala in the test suite for more examples
+ * @see Load Memories in the wiki
+ */
+ def apply[T <: Data](
+ memory: MemBase[T],
+ fileName: String,
+ hexOrBinary: MemoryLoadFileType.FileType = MemoryLoadFileType.Hex
+ ): Unit = {
+ annotate(ChiselLoadMemoryAnnotation(memory, fileName))
+ }
+}
+
+/**
+ * This transform only is activated if verilog is being generated
+ * (determined by presence of the proper emit annotation)
+ * when activated it creates additional verilog files that contain
+ * modules bound to the modules that contain an initializable memory
+ *
+ * Currently the only non-verilog based simulation that can support loading
+ * memory from a file is treadle but it does not need this transform
+ * to do that.
+ */
+//scalastyle:off method.length
+class LoadMemoryTransform extends Transform {
+ def inputForm: CircuitForm = LowForm
+ def outputForm: CircuitForm = LowForm
+
+ private var memoryCounter: Int = -1
+
+ private val bindModules: mutable.ArrayBuffer[BlackBoxInlineAnno] = new mutable.ArrayBuffer()
+
+ private val verilogEmitter: VerilogEmitter = new VerilogEmitter
+
+ /**
+ * run the pass
+ * @param circuit the circuit
+ * @param annotations all the annotations
+ * @return
+ */
+ def run(circuit: Circuit, annotations: AnnotationSeq): Circuit = {
+ val groups = annotations
+ .collect{ case m: LoadMemoryAnnotation => m }
+ .groupBy(_.target.serialize)
+ val memoryAnnotations = groups.map { case (key, annos) =>
+ if (annos.size > 1) {
+ throw new Exception(
+ s"Multiple (${annos.size} found for memory $key one LoadMemoryAnnotation is allowed per memory"
+ )
+ }
+ key -> annos.head
+ }
+
+ val modulesByName = circuit.modules.collect { case module: firrtl.ir.Module => module.name -> module }.toMap
+
+ /**
+ * walk the module and for memories that have LoadMemory annotations
+ * generate the bindable modules for verilog emission
+ *
+ * @param myModule module being searched for memories
+ */
+ def processModule(myModule: DefModule): DefModule = {
+
+ def makePath(componentName: String): String = {
+ circuit.main + "." + myModule.name + "." + componentName
+ }
+
+ def processMemory(name: String): Unit = {
+ val fullMemoryName = makePath(s"$name")
+
+ memoryAnnotations.get(fullMemoryName) match {
+ case Some(lma @ LoadMemoryAnnotation(ComponentName(componentName, moduleName), _, hexOrBinary, _)) =>
+ val writer = new java.io.StringWriter
+
+ modulesByName.get(moduleName.name).foreach { module =>
+ val renderer = verilogEmitter.getRenderer(module, modulesByName)(writer)
+ val loadFileName = lma.getFileName
+
+ memoryCounter += 1
+ val bindsToName = s"BindsTo_${memoryCounter}_${moduleName.name}"
+ renderer.emitVerilogBind(bindsToName,
+ s"""
+ |initial begin
+ | $$readmem$hexOrBinary("$loadFileName", ${myModule.name}.$componentName);
+ |end
+ """.stripMargin)
+ val inLineText = writer.toString + "\n" +
+ s"""bind ${myModule.name} $bindsToName ${bindsToName}_Inst(.*);"""
+
+ val blackBoxInline = BlackBoxInlineAnno(
+ moduleName,
+ moduleName.serialize + "." + componentName + ".v",
+ inLineText
+ )
+
+ bindModules += blackBoxInline
+ }
+
+ case _ =>
+ }
+ }
+
+ def processStatements(statement: Statement): Statement = {
+ statement match {
+ case m: DefMemory => processMemory(m.name)
+ case s => s map processStatements
+ }
+ statement
+ }
+
+ myModule match {
+ case module: firrtl.ir.Module =>
+ processStatements(module.body)
+ case _ =>
+ }
+
+ myModule
+ }
+
+ circuit map processModule
+ }
+
+ def execute(state: CircuitState): CircuitState = {
+ val isVerilog = state.annotations.exists {
+ case EmitCircuitAnnotation(emitter) =>
+ emitter == classOf[VerilogEmitter]
+ case _ =>
+ false
+ }
+ if(isVerilog) {
+ run(state.circuit, state.annotations)
+ state.copy(annotations = state.annotations ++ bindModules)
+ }
+ else {
+ state
+ }
+ }
+}
diff --git a/src/test/scala/chiselTests/Direction.scala b/src/test/scala/chiselTests/Direction.scala
index 49d0ab77a64..5f8c4f9ba15 100644
--- a/src/test/scala/chiselTests/Direction.scala
+++ b/src/test/scala/chiselTests/Direction.scala
@@ -2,11 +2,9 @@
package chiselTests
-import chisel3._
import org.scalatest._
-import org.scalatest.matchers._
-import org.scalatest.prop._
-import chisel3.testers.BasicTester
+import chisel3._
+import chisel3.util.Decoupled
class DirectionedBundle extends Bundle {
val in = Input(UInt(32.W))
@@ -62,4 +60,77 @@ class DirectionSpec extends ChiselPropSpec with Matchers {
property("Top-level forced outputs should be assignable") {
elaborate(new TopDirectionOutput)
}
+
+ import chisel3.experimental.{MultiIOModule, DataMirror, Direction}
+ import chisel3.core.SpecifiedDirection
+
+ property("Directions should be preserved through cloning and binding of Bundles") {
+ elaborate(new MultiIOModule {
+ class MyBundle extends Bundle {
+ val foo = Input(UInt(8.W))
+ val bar = Output(UInt(8.W))
+ }
+ class MyOuterBundle extends Bundle {
+ val fizz = new MyBundle
+ val buzz = Flipped(new MyBundle)
+ }
+ val a = new MyOuterBundle
+ val b = IO(a)
+ val specifiedDirs = Seq(
+ a.fizz.foo -> SpecifiedDirection.Input,
+ a.fizz.bar -> SpecifiedDirection.Output,
+ a.fizz -> SpecifiedDirection.Unspecified,
+ a.buzz.foo -> SpecifiedDirection.Input,
+ a.buzz.bar -> SpecifiedDirection.Output,
+ a.buzz -> SpecifiedDirection.Flip
+ )
+ val actualDirs = Seq(
+ b.fizz.foo -> Direction.Input,
+ b.fizz.bar -> Direction.Output,
+ b.fizz -> Direction.Bidirectional(Direction.Default),
+ b.buzz.foo -> Direction.Output,
+ b.buzz.bar -> Direction.Input,
+ b.buzz -> Direction.Bidirectional(Direction.Flipped)
+ )
+ for ((data, dir) <- specifiedDirs) {
+ DataMirror.specifiedDirectionOf(data) shouldBe (dir)
+ }
+ for ((data, dir) <- actualDirs) {
+ DataMirror.directionOf(data) shouldBe (dir)
+ }
+ }.asInstanceOf[MultiIOModule]) // The cast works around weird reflection behavior (bug?)
+ }
+
+ property("Directions should be preserved through cloning and binding of Vecs") {
+ elaborate(new MultiIOModule {
+ val a = Vec(1, Input(UInt(8.W)))
+ val b = Vec(1, a)
+ val c = Vec(1, Flipped(a))
+ val io0 = IO(b)
+ val io1 = IO(c)
+ val specifiedDirs = Seq(
+ a(0) -> SpecifiedDirection.Input,
+ b(0)(0) -> SpecifiedDirection.Input,
+ a -> SpecifiedDirection.Unspecified,
+ b -> SpecifiedDirection.Unspecified,
+ c(0) -> SpecifiedDirection.Flip,
+ c(0)(0) -> SpecifiedDirection.Input,
+ c -> SpecifiedDirection.Unspecified
+ )
+ val actualDirs = Seq(
+ io0(0)(0) -> Direction.Input,
+ io0(0) -> Direction.Input,
+ io0 -> Direction.Input,
+ io1(0)(0) -> Direction.Output,
+ io1(0) -> Direction.Output,
+ io1 -> Direction.Output
+ )
+ for ((data, dir) <- specifiedDirs) {
+ DataMirror.specifiedDirectionOf(data) shouldBe (dir)
+ }
+ for ((data, dir) <- actualDirs) {
+ DataMirror.directionOf(data) shouldBe (dir)
+ }
+ }.asInstanceOf[MultiIOModule]) // The cast works around weird reflection behavior (bug?)
+ }
}
diff --git a/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
new file mode 100644
index 00000000000..98e9496c878
--- /dev/null
+++ b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
@@ -0,0 +1,190 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import java.io.File
+
+import chisel3._
+import chisel3.util.experimental.loadMemoryFromFile
+import chisel3.util.log2Ceil
+import firrtl.FirrtlExecutionSuccess
+import firrtl.annotations.MemoryLoadFileType
+import firrtl.transforms.BlackBoxSourceHelper
+
+import org.scalatest.{FreeSpec, Matchers}
+
+class UsesThreeMems(memoryDepth: Int, memoryType: Data) extends Module {
+ val io = IO(new Bundle {
+ val address = Input(UInt(memoryType.getWidth.W))
+ val value1 = Output(memoryType)
+ val value2 = Output(memoryType)
+ val value3 = Output(memoryType)
+ })
+
+ val memory1 = Mem(memoryDepth, memoryType)
+ val memory2 = Mem(memoryDepth, memoryType)
+ val memory3 = Mem(memoryDepth, memoryType)
+ loadMemoryFromFile(memory1, "./mem1")
+ loadMemoryFromFile(memory2, "./mem1")
+ loadMemoryFromFile(memory3, "./mem1")
+
+ io.value1 := memory1(io.address)
+ io.value2 := memory2(io.address)
+ io.value3 := memory3(io.address)
+}
+
+class UsesMem(memoryDepth: Int, memoryType: Data) extends Module {
+ val io = IO(new Bundle {
+ val address = Input(UInt(memoryType.getWidth.W))
+ val value = Output(memoryType)
+ val value1 = Output(memoryType)
+ val value2 = Output(memoryType)
+ })
+
+ val memory = Mem(memoryDepth, memoryType)
+ loadMemoryFromFile(memory, "./mem1")
+
+ io.value := memory(io.address)
+
+ val low1 = Module(new UsesMemLow(memoryDepth, memoryType))
+ val low2 = Module(new UsesMemLow(memoryDepth, memoryType))
+
+ low2.io.address := io.address
+ low1.io.address := io.address
+ io.value1 := low1.io.value
+ io.value2 := low2.io.value
+}
+
+class UsesMemLow(memoryDepth: Int, memoryType: Data) extends Module {
+ val io = IO(new Bundle {
+ val address = Input(UInt(memoryType.getWidth.W))
+ val value = Output(memoryType)
+ })
+
+ val memory = Mem(memoryDepth, memoryType)
+
+ loadMemoryFromFile(memory, "./mem2")
+
+ io.value := memory(io.address)
+}
+
+class FileHasSuffix(memoryDepth: Int, memoryType: Data) extends Module {
+ val io = IO(new Bundle {
+ val address = Input(UInt(memoryType.getWidth.W))
+ val value = Output(memoryType)
+ val value2 = Output(memoryType)
+ })
+
+ val memory = Mem(memoryDepth, memoryType)
+
+ loadMemoryFromFile(memory, "./mem1.txt")
+
+ io.value := memory(io.address)
+
+ val low = Module(new UsesMemLow(memoryDepth, memoryType))
+
+ low.io.address := io.address
+ io.value2 := low.io.value
+}
+
+class MemoryShape extends Bundle {
+ val a = UInt(8.W)
+ val b = SInt(8.W)
+ val c = Bool()
+}
+
+class HasComplexMemory(memoryDepth: Int) extends Module {
+ val io = IO(new Bundle {
+ val address = Input(UInt(log2Ceil(memoryDepth).W))
+ val value = Output(new MemoryShape)
+ })
+
+ val memory = Mem(memoryDepth, new MemoryShape)
+
+ loadMemoryFromFile(memory, "./mem", MemoryLoadFileType.Hex)
+
+ io.value := memory(io.address)
+}
+
+
+/**
+ * The following tests are a bit incomplete and check that the output verilog is properly constructed
+ * For more complete working examples
+ * @see Chisel Testers LoadMemoryFromFileSpec.scala
+ */
+class LoadMemoryFromFileSpec extends FreeSpec with Matchers {
+ def fileExistsWithMem(file: File, mem: Option[String] = None): Unit = {
+ info(s"$file exists")
+ file.exists() should be (true)
+ mem.foreach( m => {
+ info(s"Memory $m is referenced in $file")
+ val found = io.Source.fromFile(file).getLines.exists { _.contains(s"""readmemh("$m"""") }
+ found should be (true)
+ } )
+ file.delete()
+ }
+
+ "Users can specify a source file to load memory from" in {
+ val testDirName = "test_run_dir/load_memory_spec"
+
+ val result = Driver.execute(
+ args = Array("-X", "verilog", "--target-dir", testDirName),
+ dut = () => new UsesMem(memoryDepth = 8, memoryType = UInt(16.W)) )
+
+ result match {
+ case ChiselExecutionSuccess(_, _, Some(FirrtlExecutionSuccess(_, _))) =>
+ val dir = new File(testDirName)
+ fileExistsWithMem(new File(dir, "UsesMem.UsesMem.memory.v"), Some("./mem1"))
+ fileExistsWithMem(new File(dir, "UsesMem.UsesMemLow.memory.v"), Some("./mem2"))
+ fileExistsWithMem(new File(dir, BlackBoxSourceHelper.fileListName))
+ case _=>
+ throw new Exception("Failed compile")
+ }
+ }
+
+ "Calling a module that loads memories from a file more than once should work" in {
+ val testDirName = "test_run_dir/load_three_memory_spec"
+
+ val result = Driver.execute(
+ args = Array("-X", "verilog", "--target-dir", testDirName),
+ dut = () => new UsesThreeMems(memoryDepth = 8, memoryType = UInt(16.W))
+ )
+
+ result match {
+ case ChiselExecutionSuccess(_, _, Some(FirrtlExecutionSuccess(_, _))) =>
+ val dir = new File(testDirName)
+ fileExistsWithMem( new File(dir, "UsesThreeMems.UsesThreeMems.memory1.v"), Some("./mem1"))
+ fileExistsWithMem( new File(dir, "UsesThreeMems.UsesThreeMems.memory2.v"), Some("./mem1"))
+ fileExistsWithMem( new File(dir, "UsesThreeMems.UsesThreeMems.memory3.v"), Some("./mem1"))
+ fileExistsWithMem( new File(dir, BlackBoxSourceHelper.fileListName))
+ case _=>
+ throw new Exception("Failed compile")
+ } }
+
+ "In this example the memory has a complex memory type containing a bundle" in {
+ val complexTestDirName = "test_run_dir/complex_memory_load"
+
+ val result = Driver.execute(
+ args = Array("-X", "verilog", "--target-dir", complexTestDirName),
+ dut = () => new HasComplexMemory(memoryDepth = 8)
+ )
+
+ result match {
+ case ChiselExecutionSuccess(_, _, Some(FirrtlExecutionSuccess(emitType, firrtlEmitted))) =>
+ val dir = new File(complexTestDirName)
+ val memoryElements = Seq("a", "b", "c")
+
+ memoryElements.foreach { element =>
+ val file = new File(dir, s"HasComplexMemory.HasComplexMemory.memory_$element.v")
+ file.exists() should be (true)
+ val fileText = io.Source.fromFile(file).getLines().mkString("\n")
+ fileText should include (s"""$$readmemh("./mem_$element", HasComplexMemory.memory_$element);""")
+ file.delete()
+ }
+
+ case _=>
+ fail(s"Failed compile")
+ }
+ }
+
+}
diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala
index 5f2927dd255..01eeb67cb93 100644
--- a/src/test/scala/chiselTests/Module.scala
+++ b/src/test/scala/chiselTests/Module.scala
@@ -62,6 +62,19 @@ class ModuleRewrap extends Module {
val inst2 = Module(inst)
}
+class ModuleWrapper(gen: => Module) extends Module {
+ val io = IO(new Bundle{})
+ val child = Module(gen)
+ override val desiredName = s"${child.desiredName}Wrapper"
+}
+
+class NullModuleWrapper extends Module {
+ val io = IO(new Bundle{})
+ override lazy val desiredName = s"${child.desiredName}Wrapper"
+ println(s"My name is ${name}")
+ val child = Module(new ModuleWire)
+}
+
class ModuleSpec extends ChiselPropSpec {
property("ModuleVec should elaborate") {
@@ -126,4 +139,11 @@ class ModuleSpec extends ChiselPropSpec {
assert(checkModule(this))
})
}
+ property("A desiredName parameterized by a submodule should work") {
+ Driver.elaborate(() => new ModuleWrapper(new ModuleWire)).name should be ("ModuleWireWrapper")
+ }
+ property("A name generating a null pointer exception should provide a good error message") {
+ (the [Exception] thrownBy (Driver.elaborate(() => new NullModuleWrapper)))
+ .getMessage should include ("desiredName of chiselTests.NullModuleWrapper is null")
+ }
}