diff options
| author | Jack Koenig | 2020-08-13 21:30:55 -0700 |
|---|---|---|
| committer | GitHub | 2020-08-13 21:30:55 -0700 |
| commit | 6ea6f61aa9ed7fa572fb74641a6943a940bd6b82 (patch) | |
| tree | 6617414fb2fe5e721dc7ea8c9b226af419318d71 /src/main/scala/chisel3 | |
| parent | 22c92b97beb3711790ea035337345e6e688fcc55 (diff) | |
Move treadle dependency to the tests (#1554)
Use inheritance to make TesterDriver Backend API extensible, then define
a TreadleBackend in the test project
Diffstat (limited to 'src/main/scala/chisel3')
| -rw-r--r-- | src/main/scala/chisel3/testers/TesterDriver.scala | 180 |
1 files changed, 51 insertions, 129 deletions
diff --git a/src/main/scala/chisel3/testers/TesterDriver.scala b/src/main/scala/chisel3/testers/TesterDriver.scala index 2a66526c..70dd4999 100644 --- a/src/main/scala/chisel3/testers/TesterDriver.scala +++ b/src/main/scala/chisel3/testers/TesterDriver.scala @@ -7,39 +7,67 @@ import java.io._ import chisel3._ import chisel3.stage.phases.{Convert, Elaborate, Emitter} import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselStage, NoRunFirrtlCompilerAnnotation} -import treadle.stage.TreadleTesterPhase 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.{CallResetAtStartupAnnotation, TreadleTesterAnnotation, WriteVcdAnnotation} 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` - */ + + private[chisel3] trait Backend extends NoTargetAnnotation with Unserializable { + def execute(t: () => BasicTester, + additionalVResources: Seq[String] = Seq(), + annotations: AnnotationSeq = Seq(), + nameHint: Option[String] = None + ): Boolean + } + case object VerilatorBackend extends Backend { + /** 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(), + annotations: AnnotationSeq = Seq(), + nameHint: Option[String] = None + ): Boolean = { + val pm = new PhaseManager( + targets = Seq(Dependency[AddImplicitTesterDirectory], + Dependency[Emitter], + Dependency[Convert])) + + val annotationsx = pm.transform(ChiselGeneratorAnnotation(finishWrapper(t)) +: annotations) + + val target: String = annotationsx.collectFirst { case FirrtlCircuitAnnotation(cir) => cir.main }.get + val path = annotationsx.collectFirst { case TargetDirAnnotation(dir) => dir }.map(new File(_)).get + + // Copy CPP harness and other Verilog sources from resources into files + val cppHarness = new File(path, "top.cpp") + copyResourceToFile("/chisel3/top.cpp", cppHarness) + // NOTE: firrtl.Driver.execute() may end up copying these same resources in its BlackBoxSourceHelper code. + // As long as the same names are used for the output files, and we avoid including duplicate files + // in BackendCompilationUtilities.verilogToCpp(), we should be okay. + // To that end, we use the same method to write the resource to the target directory. + val additionalVFiles = additionalVResources.map((name: String) => { + writeResourceToDirectory(name, path) + }) + + (new FirrtlStage).execute(Array("--compiler", "verilog"), annotationsx) + + // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe + if ((verilogToCpp(target, path, additionalVFiles, cppHarness) #&& + cppToExe(target, path)).! == 0) { + executeExpectingSuccess(target, path) + } else { + false + } + } + } + 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) - } - } + def verilatorOnly: AnnotationSeq = Seq(VerilatorBackend) /** Set the target directory to the name of the top module after elaboration */ final class AddImplicitTesterDirectory extends Phase { @@ -73,113 +101,7 @@ object TesterDriver extends BackendCompilationUtilities { } 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], - Dependency[Emitter], - Dependency[Convert])) - - val annotationsx = pm.transform(ChiselGeneratorAnnotation(finishWrapper(t)) +: annotations) - - val target: String = annotationsx.collectFirst { case FirrtlCircuitAnnotation(cir) => cir.main }.get - val path = annotationsx.collectFirst { case TargetDirAnnotation(dir) => dir }.map(new File(_)).get - - // Copy CPP harness and other Verilog sources from resources into files - val cppHarness = new File(path, "top.cpp") - copyResourceToFile("/chisel3/top.cpp", cppHarness) - // NOTE: firrtl.Driver.execute() may end up copying these same resources in its BlackBoxSourceHelper code. - // As long as the same names are used for the output files, and we avoid including duplicate files - // in BackendCompilationUtilities.verilogToCpp(), we should be okay. - // To that end, we use the same method to write the resource to the target directory. - val additionalVFiles = additionalVResources.map((name: String) => { - writeResourceToDirectory(name, path) - }) - - (new FirrtlStage).execute(Array("--compiler", "verilog"), annotationsx) - - // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe - if ((verilogToCpp(target, path, additionalVFiles, cppHarness) #&& - cppToExe(target, path)).! == 0) { - executeExpectingSuccess(target, path) - } else { - false - } - } - - 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 = (new 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 - } + backendAnnotation.execute(t, additionalVResources, annotations, nameHint) } /** |
