summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorChick Markley2020-06-30 09:39:10 -0700
committerGitHub2020-06-30 09:39:10 -0700
commit61f4abd4f8939b75ccceab5d86362c30babd1101 (patch)
treeb13d75011859e3adf806f3747c542daa9662fba1 /src/main
parenta1edc8f4cd525c8475e847ff7ddd9cb8fc1d3c51 (diff)
parent3694b092830ac0a8d1e5a6dfe9a65d88420c1962 (diff)
Merge pull request #1483 from freechipsproject/add-treadle-backend-for-tests
This adds a mechanism for the unittests to be run with the TreadleBac…
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/chisel3/testers/TesterDriver.scala151
1 files changed, 130 insertions, 21 deletions
diff --git a/src/main/scala/chisel3/testers/TesterDriver.scala b/src/main/scala/chisel3/testers/TesterDriver.scala
index 03fb1899..6231f81a 100644
--- a/src/main/scala/chisel3/testers/TesterDriver.scala
+++ b/src/main/scala/chisel3/testers/TesterDriver.scala
@@ -2,25 +2,45 @@
package chisel3.testers
-import chisel3._
import java.io._
-import chisel3.aop.Aspect
-import chisel3.experimental.RunFirrtlTransform
-import chisel3.stage.phases.{AspectPhase, Convert, Elaborate, Emitter}
-import chisel3.stage.{
- ChiselCircuitAnnotation,
- ChiselGeneratorAnnotation,
- ChiselOutputFileAnnotation,
- ChiselStage,
- DesignAnnotation
-}
-import firrtl.{Driver => _, _}
-import firrtl.options.{Dependency, Phase, PhaseManager}
+import chisel3._
+import chisel3.stage.phases.{Convert, Elaborate, Emitter}
+import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselStage, NoRunFirrtlCompilerAnnotation}
+import firrtl.AnnotationSeq
+import firrtl.annotations.NoTargetAnnotation
+import firrtl.options.{Dependency, Phase, PhaseManager, TargetDirAnnotation, Unserializable}
import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage}
import firrtl.transforms.BlackBoxSourceHelper.writeResourceToDirectory
+import treadle.executable.StopException
+import treadle.stage.TreadleTesterPhase
+import treadle.{CallResetAtStartupAnnotation, TreadleTesterAnnotation, WriteVcdAnnotation}
+//scalastyle:off magic.number method.length
object TesterDriver extends BackendCompilationUtilities {
+ var MaxTreadleCycles = 10000L
+
+ trait Backend extends NoTargetAnnotation with Unserializable
+ case object VerilatorBackend extends Backend
+ case object TreadleBackend extends Backend
+ case object NoBackend extends Backend
+
+ /*
+ Currently the only mechanism for running with the Treadle backend is to edit this
+ statement locally. To:
+ `val defaultBackend: Backend = TreadleBackend`
+ */
+ val defaultBackend: Backend = VerilatorBackend
+
+ /** Use this to force a test to be run only with backends that are restricted to verilator backend
+ */
+ def verilatorOnly: AnnotationSeq = {
+ if (defaultBackend == TreadleBackend) {
+ Seq(NoBackend)
+ } else {
+ Seq(defaultBackend)
+ }
+ }
/** Set the target directory to the name of the top module after elaboration */
final class AddImplicitTesterDirectory extends Phase {
@@ -41,9 +61,37 @@ object TesterDriver extends BackendCompilationUtilities {
/** 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,
+ def execute(t: () => BasicTester,
additionalVResources: Seq[String] = Seq(),
- annotations: AnnotationSeq = Seq()
+ annotations: AnnotationSeq = Seq(),
+ nameHint: Option[String] = None): Boolean = {
+
+ val backendAnnotations = annotations.collect { case anno: Backend => anno }
+ val backendAnnotation = if (backendAnnotations.length == 1) {
+ backendAnnotations.head
+ } else if (backendAnnotations.isEmpty) {
+ defaultBackend
+ } else {
+ throw new ChiselException(s"Only one backend annotation allowed, found: ${backendAnnotations.mkString(", ")}")
+ }
+ backendAnnotation match {
+ case TreadleBackend =>
+ executeTreadle(t, additionalVResources, annotations, nameHint)
+ case VerilatorBackend =>
+ executeVerilog(t, additionalVResources, annotations, nameHint)
+ case NoBackend =>
+ true
+ case _ =>
+ throw new ChiselException(s"Unknown backend specified: $backendAnnotation")
+ }
+ }
+
+ /** For use with modules that should successfully be elaborated by the
+ * frontend, and which can be turned into executables with assertions. */
+ def executeVerilog(t: () => BasicTester,
+ additionalVResources: Seq[String] = Seq(),
+ annotations: AnnotationSeq = Seq(),
+ nameHint: Option[String] = None
): Boolean = {
val pm = new PhaseManager(
targets = Seq(Dependency[AddImplicitTesterDirectory],
@@ -76,15 +124,76 @@ object TesterDriver extends BackendCompilationUtilities {
false
}
}
+
+ //scalastyle:off cyclomatic.complexity method.length
+ def executeTreadle(t: () => BasicTester,
+ additionalVResources: Seq[String] = Seq(),
+ annotations: AnnotationSeq = Seq(),
+ nameHint: Option[String] = None): Boolean = {
+ val generatorAnnotation = chisel3.stage.ChiselGeneratorAnnotation(t)
+
+ // This provides an opportunity to translate from top level generic flags to backend specific annos
+ var annotationSeq = annotations :+ WriteVcdAnnotation
+
+ // This produces a chisel circuit annotation, a later pass will generate a firrtl circuit
+ // Can't do both at once currently because generating the latter deletes the former
+ annotationSeq = (new chisel3.stage.phases.Elaborate).transform(annotationSeq :+ generatorAnnotation)
+
+ val circuit = annotationSeq.collect { case x: ChiselCircuitAnnotation => x }.head.circuit
+
+ val targetName: File = createTestDirectory(circuit.name)
+
+ if (!annotationSeq.exists(_.isInstanceOf[NoTargetAnnotation])) {
+ annotationSeq = annotationSeq :+ TargetDirAnnotation(targetName.getPath)
+ }
+ if (!annotationSeq.exists { case CallResetAtStartupAnnotation => true ; case _ => false }) {
+ annotationSeq = annotationSeq :+ CallResetAtStartupAnnotation
+ }
+
+ // This generates the firrtl circuit needed by the TreadleTesterPhase
+ annotationSeq = (new ChiselStage).run(
+ annotationSeq ++ Seq(NoRunFirrtlCompilerAnnotation)
+ )
+
+ // This generates a TreadleTesterAnnotation with a treadle tester instance
+ annotationSeq = TreadleTesterPhase.transform(annotationSeq)
+
+ val treadleTester = annotationSeq.collectFirst { case TreadleTesterAnnotation(t) => t }.getOrElse(
+ throw new Exception(
+ s"TreadleTesterPhase could not build a treadle tester from these annotations" +
+ annotationSeq.mkString("Annotations:\n", "\n ", "")
+ )
+ )
+
+ try {
+ var cycle = 0L
+ while (cycle < MaxTreadleCycles) {
+ cycle += 1
+ treadleTester.step()
+ }
+ throw new ChiselException(s"Treadle backend exceeded MaxTreadleCycles ($MaxTreadleCycles)")
+ } catch {
+ case _: StopException =>
+ }
+ treadleTester.finish
+
+ treadleTester.getStopResult match {
+ case None => true
+ case Some(0) => true
+ case _ => 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
- }
+ def finishWrapper(test: () => BasicTester): () => BasicTester = { () =>
+ {
+ val tester = test()
+ tester.finish()
+ tester
}
+ }
+
}