diff options
| author | Jack Koenig | 2018-02-28 17:40:53 -0800 |
|---|---|---|
| committer | GitHub | 2018-02-28 17:40:53 -0800 |
| commit | 46553432aaf65cff131e59081d57dabe16c2ab55 (patch) | |
| tree | 2a64125046b36808a5a89c18f98204394c27ccd8 /src | |
| parent | 97871178cb511063965f971b768f91c289c4776f (diff) | |
Refactor Annotations (#767)
* Generalize ChiselAnnotation
This allows us to delay creation of Annotations till elaboration is
complete. Also update all annotation-related code.
* Add RunFirrtlTransform
Use a Chisel-specific RunFirrtlTransform API to preserve behavior of old
ChiselAnnotation (now called ChiselLegacyAnnotation)
* Use unique test directories in ChiselRunners.compile
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/chisel3/Driver.scala | 22 | ||||
| -rw-r--r-- | src/main/scala/chisel3/package.scala | 3 | ||||
| -rw-r--r-- | src/main/scala/chisel3/util/BlackBoxUtils.scala | 17 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/AnnotatingDiamondSpec.scala | 78 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/AnnotationNoDedup.scala | 18 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/ChiselSpec.scala | 6 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/DriverSpec.scala | 4 |
7 files changed, 80 insertions, 68 deletions
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala index dae921ab..25d25425 100644 --- a/src/main/scala/chisel3/Driver.scala +++ b/src/main/scala/chisel3/Driver.scala @@ -3,13 +3,14 @@ package chisel3 import chisel3.internal.firrtl.Emitter -import chisel3.experimental.RawModule +import chisel3.experimental.{RawModule, RunFirrtlTransform} import java.io._ import net.jcazevedo.moultingyaml._ import internal.firrtl._ import firrtl._ +import firrtl.annotations.{Annotation, JsonProtocol} import firrtl.util.{ BackendCompilationUtilities => FirrtlBackendCompilationUtilities } import _root_.firrtl.annotations.AnnotationYamlProtocol._ @@ -153,9 +154,10 @@ object Driver extends BackendCompilationUtilities { w.write(firrtlString) w.close() - val annotationFile = new File(optionsManager.getBuildFileName("anno")) + val annotationFile = new File(optionsManager.getBuildFileName("anno.json")) val af = new FileWriter(annotationFile) - af.write(circuit.annotations.toArray.toYaml.prettyPrint) + val firrtlAnnos = circuit.annotations.map(_.toFirrtl) + af.write(JsonProtocol.serialize(firrtlAnnos)) af.close() /** Find the set of transform classes associated with annotations then @@ -164,16 +166,16 @@ object Driver extends BackendCompilationUtilities { * transform being instantiated */ val transforms = circuit.annotations - .map(_.transform) - .distinct - .filterNot(_ == classOf[firrtl.Transform]) - .map { transformClass: Class[_ <: Transform] => - transformClass.newInstance() - } + .collect { case anno: RunFirrtlTransform => anno.transformClass } + .distinct + .filterNot(_ == classOf[firrtl.Transform]) + .map { transformClass: Class[_ <: Transform] => + transformClass.newInstance() + } /* This passes the firrtl source and annotations directly to firrtl */ optionsManager.firrtlOptions = optionsManager.firrtlOptions.copy( firrtlSource = Some(firrtlString), - annotations = optionsManager.firrtlOptions.annotations ++ circuit.annotations.toList, + annotations = optionsManager.firrtlOptions.annotations ++ firrtlAnnos, customTransforms = optionsManager.firrtlOptions.customTransforms ++ transforms.toList) val firrtlExecutionResult = if(chiselOptions.runFirrtlCompiler) { diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala index 973ad026..b3a9f54b 100644 --- a/src/main/scala/chisel3/package.scala +++ b/src/main/scala/chisel3/package.scala @@ -439,6 +439,9 @@ package object chisel3 { // scalastyle:ignore package.object.name type ChiselAnnotation = chisel3.core.ChiselAnnotation val ChiselAnnotation = chisel3.core.ChiselAnnotation + type RunFirrtlTransform = chisel3.core.RunFirrtlTransform + + val annotate = chisel3.core.annotate val DataMirror = chisel3.core.DataMirror val requireIsHardware = chisel3.core.requireIsHardware diff --git a/src/main/scala/chisel3/util/BlackBoxUtils.scala b/src/main/scala/chisel3/util/BlackBoxUtils.scala index fbcf4a59..fa62184a 100644 --- a/src/main/scala/chisel3/util/BlackBoxUtils.scala +++ b/src/main/scala/chisel3/util/BlackBoxUtils.scala @@ -3,14 +3,18 @@ package chisel3.util import chisel3._ -import chisel3.core.ChiselAnnotation -import firrtl.transforms.{BlackBoxInline, BlackBoxResource, BlackBoxSourceHelper} +import chisel3.experimental.{ChiselAnnotation, RunFirrtlTransform} +import firrtl.transforms.{BlackBoxResourceAnno, BlackBoxInlineAnno, BlackBoxSourceHelper} trait HasBlackBoxResource extends BlackBox { self: BlackBox => def setResource(blackBoxResource: String): Unit = { - annotate(ChiselAnnotation(self, classOf[BlackBoxSourceHelper], BlackBoxResource(blackBoxResource).serialize)) + val anno = new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl = BlackBoxResourceAnno(self.toNamed, blackBoxResource) + def transformClass = classOf[BlackBoxSourceHelper] + } + chisel3.experimental.annotate(anno) } } @@ -18,7 +22,10 @@ trait HasBlackBoxInline extends BlackBox { self: BlackBox => def setInline(blackBoxName: String, blackBoxInline: String): Unit = { - annotate(ChiselAnnotation( - self, classOf[BlackBoxSourceHelper], BlackBoxInline(blackBoxName, blackBoxInline).serialize)) + val anno = new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl = BlackBoxInlineAnno(self.toNamed, blackBoxName, blackBoxInline) + def transformClass = classOf[BlackBoxSourceHelper] + } + chisel3.experimental.annotate(anno) } } diff --git a/src/test/scala/chiselTests/AnnotatingDiamondSpec.scala b/src/test/scala/chiselTests/AnnotatingDiamondSpec.scala index f792c56f..e88d475e 100644 --- a/src/test/scala/chiselTests/AnnotatingDiamondSpec.scala +++ b/src/test/scala/chiselTests/AnnotatingDiamondSpec.scala @@ -3,47 +3,50 @@ package chiselTests import chisel3._ -import chisel3.experimental.ChiselAnnotation +import chisel3.experimental.{annotate, ChiselAnnotation, RunFirrtlTransform} import chisel3.internal.InstanceId import chisel3.testers.BasicTester -import firrtl.{CircuitForm, CircuitState, LowForm, Transform} -import firrtl.annotations.{Annotation, ModuleName, Named} +import firrtl.{CircuitState, LowForm, Transform} +import firrtl.annotations.{ + Annotation, + SingleTargetAnnotation, + ModuleName, + Named +} import org.scalatest._ -//scalastyle:off magic.number -/** - * This and the Identity transform class are a highly schematic implementation of a - * library implementation of (i.e. code outside of firrtl itself) +/** These annotations and the IdentityTransform class serve as an example of how to write a + * Chisel/Firrtl library */ -object IdentityAnnotation { - def apply(target: Named, value: String): Annotation = Annotation(target, classOf[IdentityTransform], value) - - def unapply(a: Annotation): Option[(Named, String)] = a match { - case Annotation(named, t, value) if t == classOf[IdentityTransform] => Some((named, value)) - case _ => None +case class IdentityAnnotation(target: Named, value: String) extends SingleTargetAnnotation[Named] { + def duplicate(n: Named) = this.copy(target = n) +} +/** ChiselAnnotation that corresponds to the above FIRRTL annotation */ +case class IdentityChiselAnnotation(target: InstanceId, value: String) + extends ChiselAnnotation with RunFirrtlTransform { + def toFirrtl = IdentityAnnotation(target.toNamed, value) + def transformClass = classOf[IdentityTransform] +} +object identify { + def apply(component: InstanceId, value: String): Unit = { + val anno = IdentityChiselAnnotation(component, value) + annotate(anno) } } class IdentityTransform extends Transform { - override def inputForm: CircuitForm = LowForm + def inputForm = LowForm + def outputForm = LowForm - override def outputForm: CircuitForm = LowForm - - override def execute(state: CircuitState): CircuitState = { - getMyAnnotations(state) match { - case Nil => state - case myAnnotations => - state + def execute(state: CircuitState): CircuitState = { + val annosx = state.annotations.map { + case IdentityAnnotation(t, value) => IdentityAnnotation(t, value + ":seen") + case other => other } + state.copy(annotations = annosx) } } -trait IdentityAnnotator { - self: Module => - def identify(component: InstanceId, value: String): Unit = { - annotate(ChiselAnnotation(component, classOf[IdentityTransform], value)) - } -} /** A diamond circuit Top instantiates A and B and both A and B instantiate C * Illustrations of annotations of various components and modules in both * relative and absolute cases @@ -54,7 +57,7 @@ trait IdentityAnnotator { * This class has parameterizable widths, it will generate different hardware * @param widthC io width */ -class ModC(widthC: Int) extends Module with IdentityAnnotator { +class ModC(widthC: Int) extends Module { val io = IO(new Bundle { val in = Input(UInt(widthC.W)) val out = Output(UInt(widthC.W)) @@ -71,7 +74,7 @@ class ModC(widthC: Int) extends Module with IdentityAnnotator { * based on it's parameter * @param annoParam parameter is only used in annotation not in circuit */ -class ModA(annoParam: Int) extends Module with IdentityAnnotator { +class ModA(annoParam: Int) extends Module { val io = IO(new Bundle { val in = Input(UInt()) val out = Output(UInt()) @@ -86,7 +89,7 @@ class ModA(annoParam: Int) extends Module with IdentityAnnotator { identify(io.out, s"ModA.io.out(ignore_param)") } -class ModB(widthB: Int) extends Module with IdentityAnnotator{ +class ModB(widthB: Int) extends Module { val io = IO(new Bundle { val in = Input(UInt(widthB.W)) val out = Output(UInt(widthB.W)) @@ -98,7 +101,7 @@ class ModB(widthB: Int) extends Module with IdentityAnnotator{ identify(io.in, s"modB.io.in annotated from inside modB") } -class TopOfDiamond extends Module with IdentityAnnotator { +class TopOfDiamond extends Module { val io = IO(new Bundle { val in = Input(UInt(32.W)) val out = Output(UInt(32.W)) @@ -128,9 +131,6 @@ class DiamondTester extends BasicTester { } class AnnotatingDiamondSpec extends FreeSpec with Matchers { - def findAnno(as: Seq[Annotation], name: String): Option[Annotation] = { - as.find { a => a.targetString == name } - } """ |Diamond is an example of a module that has two sub-modules A and B who both instantiate their @@ -144,16 +144,16 @@ class AnnotatingDiamondSpec extends FreeSpec with Matchers { Driver.execute(Array("--target-dir", "test_run_dir"), () => new TopOfDiamond) match { case ChiselExecutionSuccess(Some(circuit), emitted, _) => - val annos = circuit.annotations - annos.length should be (10) + val annos = circuit.annotations.map(_.toFirrtl) + annos.count(_.isInstanceOf[IdentityAnnotation]) should be (10) annos.count { - case Annotation(ModuleName(name, _), _, annoValue) => name == "ModC" && annoValue == "ModC(16)" + case IdentityAnnotation(ModuleName("ModC", _), "ModC(16)") => true case _ => false } should be (1) annos.count { - case Annotation(ModuleName(name, _), _, annoValue) => name == "ModC_1" && annoValue == "ModC(32)" + case IdentityAnnotation(ModuleName("ModC_1", _), "ModC(32)") => true case _ => false } should be (1) case _ => @@ -161,4 +161,4 @@ class AnnotatingDiamondSpec extends FreeSpec with Matchers { } } } -}
\ No newline at end of file +} diff --git a/src/test/scala/chiselTests/AnnotationNoDedup.scala b/src/test/scala/chiselTests/AnnotationNoDedup.scala index 93167f69..d93da31f 100644 --- a/src/test/scala/chiselTests/AnnotationNoDedup.scala +++ b/src/test/scala/chiselTests/AnnotationNoDedup.scala @@ -3,16 +3,14 @@ package chiselTests import chisel3._ -import chisel3.experimental.ChiselAnnotation +import chisel3.experimental.{annotate, ChiselAnnotation} import firrtl.FirrtlExecutionSuccess -import firrtl.transforms.DedupModules +import firrtl.transforms.NoDedupAnnotation import org.scalatest.{FreeSpec, Matchers} -trait NoDedupAnnotator { - self: Module => - - def doNotDedup(module: Module): Unit = { - annotate(ChiselAnnotation(module, classOf[DedupModules], "nodedup!")) +object doNotDedup { + def apply(module: Module): Unit = { + annotate(new ChiselAnnotation { def toFirrtl = NoDedupAnnotation(module.toNamed) }) } } @@ -24,7 +22,7 @@ class MuchUsedModule extends Module { io.out := io.in +% 1.U } -class UsesMuchUsedModule(addAnnos: Boolean) extends Module with NoDedupAnnotator{ +class UsesMuchUsedModule(addAnnos: Boolean) extends Module { val io = IO(new Bundle { val in = Input(UInt(16.W)) val out = Output(UInt(16.W)) @@ -49,7 +47,7 @@ class UsesMuchUsedModule(addAnnos: Boolean) extends Module with NoDedupAnnotator class AnnotationNoDedup extends FreeSpec with Matchers { "Firrtl provides transform that reduces identical modules to a single instance" - { - "Annotations can be added which will defeat this deduplication for specific modules instances" in { + "Annotations can be added which will prevent this deduplication for specific modules instances" in { Driver.execute(Array("-X", "low", "--target-dir", "test_run_dir"), () => new UsesMuchUsedModule(addAnnos = true)) match { case ChiselExecutionSuccess(_, _, Some(firrtlResult: FirrtlExecutionSuccess)) => val lowFirrtl = firrtlResult.emitted @@ -62,7 +60,7 @@ class AnnotationNoDedup extends FreeSpec with Matchers { case _ => } } - "Turning off these nnotations dedup all the occurrences" in { + "Turning off these annotations dedups all the occurrences" in { Driver.execute(Array("-X", "low", "--target-dir", "test_run_dir"), () => new UsesMuchUsedModule(addAnnos = false)) match { case ChiselExecutionSuccess(_, _, Some(firrtlResult: FirrtlExecutionSuccess)) => val lowFirrtl = firrtlResult.emitted diff --git a/src/test/scala/chiselTests/ChiselSpec.scala b/src/test/scala/chiselTests/ChiselSpec.scala index 14672d68..661cf00e 100644 --- a/src/test/scala/chiselTests/ChiselSpec.scala +++ b/src/test/scala/chiselTests/ChiselSpec.scala @@ -16,9 +16,10 @@ import firrtl.{ FirrtlExecutionSuccess, FirrtlExecutionFailure } +import firrtl.util.BackendCompilationUtilities /** Common utility functions for Chisel unit tests. */ -trait ChiselRunners extends Assertions { +trait ChiselRunners extends Assertions with BackendCompilationUtilities { def runTester(t: => BasicTester, additionalVResources: Seq[String] = Seq()): Boolean = { TesterDriver.execute(() => t, additionalVResources) } @@ -43,9 +44,10 @@ trait ChiselRunners extends Assertions { * @return the Verilog code as a string. */ def compile(t: => RawModule): String = { + val testDir = createTestDirectory(this.getClass.getSimpleName) val manager = new ExecutionOptionsManager("compile") with HasFirrtlOptions with HasChiselExecutionOptions { - commonOptions = CommonOptions(targetDirName = "test_run_dir") + commonOptions = CommonOptions(targetDirName = testDir.toString) } Driver.execute(manager, () => t) match { diff --git a/src/test/scala/chiselTests/DriverSpec.scala b/src/test/scala/chiselTests/DriverSpec.scala index 796668e3..612bdef2 100644 --- a/src/test/scala/chiselTests/DriverSpec.scala +++ b/src/test/scala/chiselTests/DriverSpec.scala @@ -25,7 +25,7 @@ class DriverSpec extends FreeSpec with Matchers { val targetDir = "." Driver.execute(Array.empty[String], () => new DummyModule) match { case ChiselExecutionSuccess(_, _, Some(_: FirrtlExecutionSuccess)) => - val exts = List("anno", "fir", "v") + val exts = List("anno.json", "fir", "v") for (ext <- exts) { val dummyOutput = new File(targetDir, "DummyModule" + "." + ext) dummyOutput.exists() should be(true) @@ -41,7 +41,7 @@ class DriverSpec extends FreeSpec with Matchers { val targetDir = "local-build" Driver.execute(Array("-tn", "dm", "-td", targetDir), () => new DummyModule) match { case ChiselExecutionSuccess(_, _, Some(_: FirrtlExecutionSuccess)) => - val exts = List("anno", "fir", "v") + val exts = List("anno.json", "fir", "v") for (ext <- exts) { val dummyOutput = new File(targetDir, "dm" + "." + ext) dummyOutput.exists() should be(true) |
