From 26096e07f6ce3e12b2114132c2859ef56fb0cfaf Mon Sep 17 00:00:00 2001 From: Albert Magyar Date: Tue, 30 Jul 2019 22:42:05 -0700 Subject: [PATCH] Coordinate Top and Harness generation (#63) * Coordinate Top and Harness generation * Update to use .f filename override annotations * Move top generation to def to help GC --- .../src/main/scala/transforms/Generate.scala | 158 +++++++++++------- 1 file changed, 102 insertions(+), 56 deletions(-) diff --git a/tapeout/src/main/scala/transforms/Generate.scala b/tapeout/src/main/scala/transforms/Generate.scala index ce261a31..e8a64eb7 100644 --- a/tapeout/src/main/scala/transforms/Generate.scala +++ b/tapeout/src/main/scala/transforms/Generate.scala @@ -8,6 +8,8 @@ import firrtl.passes.Pass import java.io.File import firrtl.annotations.AnnotationYamlProtocol._ +import firrtl.passes.memlib.ReplSeqMemAnnotation +import firrtl.transforms.BlackBoxResourceFileNameAnno import net.jcazevedo.moultingyaml._ import com.typesafe.scalalogging.LazyLogging @@ -60,6 +62,17 @@ trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => "use this to set topAnnoOut" } + parser.opt[String]("top-dotf-out") + .abbr("tdf") + .valueName("") + .foreach { x => + tapeoutOptions = tapeoutOptions.copy( + topDotfOut = Some(x) + ) + }.text { + "use this to set the filename for the top resource .f file" + } + parser.opt[String]("harness-top") .abbr("tht") .valueName("") @@ -93,6 +106,28 @@ trait HasTapeoutOptions { self: ExecutionOptionsManager with HasFirrtlOptions => "use this to set harnessAnnoOut" } + parser.opt[String]("harness-dotf-out") + .abbr("hdf") + .valueName("") + .foreach { x => + tapeoutOptions = tapeoutOptions.copy( + harnessDotfOut = Some(x) + ) + }.text { + "use this to set the filename for the harness resource .f file" + } + + parser.opt[String]("harness-conf") + .abbr("thconf") + .valueName ("") + .foreach { x => + tapeoutOptions = tapeoutOptions.copy( + harnessConf = Some(x) + ) + }.text { + "use this to set the harness conf file location" + } + } case class TapeoutOptions( @@ -100,9 +135,12 @@ case class TapeoutOptions( synTop: Option[String] = None, topFir: Option[String] = None, topAnnoOut: Option[String] = None, + topDotfOut: Option[String] = None, harnessTop: Option[String] = None, harnessFir: Option[String] = None, - harnessAnnoOut: Option[String] = None + harnessAnnoOut: Option[String] = None, + harnessDotfOut: Option[String] = None, + harnessConf: Option[String] = None ) extends LazyLogging // Requires two phases, one to collect modules below synTop in the hierarchy @@ -123,79 +161,88 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => // FIRRTL options lazy val annoFiles = firrtlOptions.annotationFileNames - private def topTransforms: Seq[Transform] = { + lazy val topTransforms: Seq[Transform] = { Seq( new ReParentCircuit(synTop.get), new RemoveUnusedModules ) } + lazy val topOptions = firrtlOptions.copy( + customTransforms = firrtlOptions.customTransforms ++ topTransforms, + annotations = firrtlOptions.annotations ++ tapeoutOptions.topDotfOut.map(BlackBoxResourceFileNameAnno(_)) + ) - private def harnessTransforms: Seq[Transform] = { + class AvoidExtModuleCollisions(mustLink: Seq[ExtModule]) extends Transform { + def inputForm = HighForm + def outputForm = HighForm + def execute(state: CircuitState): CircuitState = { + state.copy(circuit = state.circuit.copy(modules = state.circuit.modules ++ mustLink)) + } + } + + private def harnessTransforms(topExtModules: Seq[ExtModule]): Seq[Transform] = { // XXX this is a hack, we really should be checking the masters to see if they are ExtModules val externals = Set(harnessTop.get, synTop.get, "SimSerial", "SimDTM") Seq( new ConvertToExtMod((m) => m.name == synTop.get), new RemoveUnusedModules, + new AvoidExtModuleCollisions(topExtModules), new RenameModulesAndInstances((old) => if (externals contains old) old else (old + "_in" + harnessTop.get)) ) } - // Top Generation - protected def executeTop: Unit = { - - optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy( - customTransforms = firrtlOptions.customTransforms ++ topTransforms - ) - - val result = firrtl.Driver.execute(optionsManager) - - result match { - case x: FirrtlExecutionSuccess => - tapeoutOptions.topFir.foreach { firFile => - val outputFile = new java.io.PrintWriter(firFile) - outputFile.write(x.circuitState.circuit.serialize) - outputFile.close() - } - tapeoutOptions.topAnnoOut.foreach { annoFile => - val outputFile = new java.io.PrintWriter(annoFile) - outputFile.write(JsonProtocol.serialize(x.circuitState.annotations.filter(_ match { - case ea: EmittedAnnotation[_] => false - case fca: FirrtlCircuitAnnotation => false - case _ => true - }))) - outputFile.close() - } - case _ => + // Dump firrtl and annotation files + protected def dump(res: FirrtlExecutionSuccess, firFile: Option[String], annoFile: Option[String]): Unit = { + firFile.foreach { firPath => + val outputFile = new java.io.PrintWriter(firPath) + outputFile.write(res.circuitState.circuit.serialize) + outputFile.close() + } + annoFile.foreach { annoPath => + val outputFile = new java.io.PrintWriter(annoPath) + outputFile.write(JsonProtocol.serialize(res.circuitState.annotations.filter(_ match { + case ea: EmittedAnnotation[_] => false + case fca: FirrtlCircuitAnnotation => false + case _ => true + }))) + outputFile.close() } - } - // Harness Generation - protected def executeHarness: Unit = { - - optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy( - customTransforms = firrtlOptions.customTransforms ++ harnessTransforms - ) - + // Top Generation + protected def executeTop(): Seq[ExtModule] = { + optionsManager.firrtlOptions = topOptions val result = firrtl.Driver.execute(optionsManager) - result match { case x: FirrtlExecutionSuccess => - tapeoutOptions.harnessFir.foreach { firFile => - val outputFile = new java.io.PrintWriter(firFile) - outputFile.write(x.circuitState.circuit.serialize) - outputFile.close() - } - tapeoutOptions.harnessAnnoOut.foreach { annoFile => - val outputFile = new java.io.PrintWriter(annoFile) - outputFile.write(JsonProtocol.serialize(x.circuitState.annotations.filter(_ match { - case ea: EmittedAnnotation[_] => false - case fca: FirrtlCircuitAnnotation => false - case _ => true - }))) - outputFile.close() - } + dump(x, tapeoutOptions.topFir, tapeoutOptions.topAnnoOut) + x.circuitState.circuit.modules.collect{ case e: ExtModule => e } + case _ => + throw new Exception("executeTop failed on illegal FIRRTL input!") + } + } + + // Top and harness generation + protected def executeTopAndHarness(): Unit = { + // Execute top and get list of ExtModules to avoid collisions + val topExtModules = executeTop() + + // For harness run, change some firrtlOptions (below) for harness phase + // customTransforms: setup harness transforms, add AvoidExtModuleCollisions + // outputFileNameOverride: change to harnessOutput + // conf file must change to harnessConf by mapping annotations + optionsManager.firrtlOptions = firrtlOptions.copy( + customTransforms = firrtlOptions.customTransforms ++ harnessTransforms(topExtModules), + outputFileNameOverride = tapeoutOptions.harnessOutput.get, + annotations = firrtlOptions.annotations.map({ + case ReplSeqMemAnnotation(i, o) => ReplSeqMemAnnotation(i, tapeoutOptions.harnessConf.get) + case a => a + }) ++ tapeoutOptions.harnessDotfOut.map(BlackBoxResourceFileNameAnno(_)) + ) + val harnessResult = firrtl.Driver.execute(optionsManager) + harnessResult match { + case x: FirrtlExecutionSuccess => dump(x, tapeoutOptions.harnessFir, tapeoutOptions.harnessAnnoOut) case _ => } } @@ -203,10 +250,9 @@ sealed trait GenerateTopAndHarnessApp extends LazyLogging { this: App => object GenerateTop extends App with GenerateTopAndHarnessApp { // Only need a single phase to generate the top module - executeTop + executeTop() } -object GenerateHarness extends App with GenerateTopAndHarnessApp { - // Do minimal work for the first phase to generate test harness - executeHarness +object GenerateTopAndHarness extends App with GenerateTopAndHarnessApp { + executeTopAndHarness() }