summaryrefslogtreecommitdiff
path: root/src/main/scala/chisel3/testers
diff options
context:
space:
mode:
authorJim Lawson2016-07-06 10:01:23 -0700
committerJim Lawson2016-07-18 15:17:56 -0700
commitc5f9ea3133ef363ff8944e17d94fea79767b6bed (patch)
treecc80a6df1eb58f0feaf9f138eb7fe261ccda4ea2 /src/main/scala/chisel3/testers
parent53813f61b7dfe246d214ab966739d01c65c8ecb0 (diff)
Rename "Chisel" to "chisel3" (only git mv).
Diffstat (limited to 'src/main/scala/chisel3/testers')
-rw-r--r--src/main/scala/chisel3/testers/BasicTester.scala38
-rw-r--r--src/main/scala/chisel3/testers/TesterDriver.scala68
2 files changed, 106 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/testers/BasicTester.scala b/src/main/scala/chisel3/testers/BasicTester.scala
new file mode 100644
index 00000000..b8c1494a
--- /dev/null
+++ b/src/main/scala/chisel3/testers/BasicTester.scala
@@ -0,0 +1,38 @@
+// See LICENSE for license details.
+
+package Chisel.testers
+import Chisel._
+
+import scala.language.experimental.macros
+
+import internal._
+import internal.Builder.pushCommand
+import internal.firrtl._
+import internal.sourceinfo.SourceInfo
+
+class BasicTester extends Module {
+ // The testbench has no IOs, rather it should communicate using printf, assert, and stop.
+ val io = new Bundle()
+
+ def popCount(n: Long): Int = n.toBinaryString.count(_=='1')
+
+ /** Ends the test reporting success.
+ *
+ * Does not fire when in reset (defined as the encapsulating Module's
+ * reset). If your definition of reset is not the encapsulating Module's
+ * reset, you will need to gate this externally.
+ */
+ def stop()(implicit sourceInfo: SourceInfo) {
+ // TODO: rewrite this using library-style SourceInfo passing.
+ when (!reset) {
+ pushCommand(Stop(sourceInfo, Node(clock), 0))
+ }
+ }
+
+ /** The finish method provides a hook that subclasses of BasicTester can use to
+ * alter a circuit after their constructor has been called.
+ * For example, a specialized tester subclassing BasicTester could override finish in order to
+ * add flow control logic for a decoupled io port of a device under test
+ */
+ def finish(): Unit = {}
+}
diff --git a/src/main/scala/chisel3/testers/TesterDriver.scala b/src/main/scala/chisel3/testers/TesterDriver.scala
new file mode 100644
index 00000000..a56bb8b7
--- /dev/null
+++ b/src/main/scala/chisel3/testers/TesterDriver.scala
@@ -0,0 +1,68 @@
+// See LICENSE for license details.
+
+package Chisel.testers
+import Chisel._
+import scala.io.Source
+import scala.sys.process._
+import java.io._
+
+object TesterDriver extends BackendCompilationUtilities {
+ /** Copy the contents of a resource to a destination file.
+ */
+ def copyResourceToFile(name: String, file: File) {
+ val in = getClass().getResourceAsStream(name)
+ if (in == null) {
+ throw new FileNotFoundException(s"Resource '$name'")
+ }
+ val out = new FileOutputStream(file)
+ Iterator.continually(in.read).takeWhile(-1 !=).foreach(out.write)
+ out.close()
+ }
+
+ /** For use with modules that should successfully be elaborated by the
+ * frontend, and which can be turned into executables with assertions. */
+ def execute(t: () => BasicTester, additionalVResources: Seq[String] = Seq()): Boolean = {
+ // Invoke the chisel compiler to get the circuit's IR
+ val circuit = Driver.elaborate(finishWrapper(t))
+
+ // Set up a bunch of file handlers based on a random temp filename,
+ // plus the quirks of Verilator's naming conventions
+ val target = circuit.name
+
+ val path = createTempDirectory(target)
+ val fname = new File(path, target)
+
+ // For now, dump the IR out to a file
+ Driver.dumpFirrtl(circuit, Some(new File(fname.toString + ".fir")))
+
+ // Copy CPP harness and other Verilog sources from resources into files
+ val cppHarness = new File(path, "top.cpp")
+ copyResourceToFile("/top.cpp", cppHarness)
+ val additionalVFiles = additionalVResources.map((name: String) => {
+ val mangledResourceName = name.replace("/", "_")
+ val out = new File(path, mangledResourceName)
+ copyResourceToFile(name, out)
+ out
+ })
+
+ // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe
+ if ((firrtlToVerilog(target, path) #&&
+ verilogToCpp(target, target, path, additionalVFiles, cppHarness) #&&
+ cppToExe(target, path)).! == 0) {
+ executeExpectingSuccess(target, path)
+ } else {
+ false
+ }
+ }
+ /**
+ * Calls the finish method of an BasicTester or a class that extends it.
+ * The finish method is a hook for code that augments the circuit built in the constructor.
+ */
+ def finishWrapper(test: () => BasicTester): () => BasicTester = {
+ () => {
+ val tester = test()
+ tester.finish()
+ tester
+ }
+ }
+}