From ee0f27c50f8d029721e69c0e7a7bd47b9a4c1d02 Mon Sep 17 00:00:00 2001 From: Schuyler Eldridge Date: Mon, 20 Aug 2018 23:31:22 -0400 Subject: Add InlineInstance API This adds a new trait, InlineInstance, to chisel3.util.experimental. This trait, when mixed into a specific module or instance, will "inline" that module, i.e., "collapse a module while preserving it's submodules." This includes testing (InlineSpec) and ScalaDoc documentation. Signed-off-by: Schuyler Eldridge --- .../scala/chisel3/util/experimental/Inline.scala | 50 +++++++++++++++++++ src/test/scala/chiselTests/InlineSpec.scala | 57 ++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/main/scala/chisel3/util/experimental/Inline.scala create mode 100644 src/test/scala/chiselTests/InlineSpec.scala diff --git a/src/main/scala/chisel3/util/experimental/Inline.scala b/src/main/scala/chisel3/util/experimental/Inline.scala new file mode 100644 index 00000000..4039f3ed --- /dev/null +++ b/src/main/scala/chisel3/util/experimental/Inline.scala @@ -0,0 +1,50 @@ +// See LICENSE for license details. + +package chisel3.util.experimental + +import chisel3._ +import chisel3.internal.InstanceId +import chisel3.experimental.{BaseModule, ChiselAnnotation, RunFirrtlTransform} +import firrtl.Transform +import firrtl.passes.{InlineAnnotation, InlineInstances} +import firrtl.transforms.{NoDedupAnnotation, FlattenAnnotation, Flatten} +import firrtl.annotations.{CircuitName, ModuleName, ComponentName, Annotation} + +/** Inlines an instance of a module + * + * @example {{{ + * trait Internals { this: Module => + * val io = IO(new Bundle{ val a = Input(Bool()) }) + * } + * class Sub extends Module with Internals + * trait HasSub { this: Module with Internals => + * val sub = Module(new Sub) + * sub.io.a := io.a + * } + * /* InlineInstance is mixed directly into Foo's definition. Every instance + * * of this will be inlined. */ + * class Foo extends Module with Internals with InlineInstance with HasSub + * /* Bar will, by default, not be inlined */ + * class Bar extends Module with Internals with HasSub + * /* The resulting instances will be: + * - Top + * - Top.x$sub + * - Top.y$sub + * - Top.z + * - Top.z.sub */ + * class Top extends Module with Internals { + * val x = Module(new Foo) // x will be inlined + * val y = Module(new Bar with InlineInstance) // y will also be inlined + * val z = Module(new Bar) // z will not be inlined + * Seq(x, y, z).map(_.io.a := io.a) + * } + * }}} + */ +trait InlineInstance { self: BaseModule => + Seq(new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl: Annotation = InlineAnnotation(self.toNamed) + def transformClass: Class[_ <: Transform] = classOf[InlineInstances] }, + new ChiselAnnotation { + def toFirrtl: Annotation = NoDedupAnnotation(self.toNamed) }) + .map(chisel3.experimental.annotate(_)) +} diff --git a/src/test/scala/chiselTests/InlineSpec.scala b/src/test/scala/chiselTests/InlineSpec.scala new file mode 100644 index 00000000..4482d9ec --- /dev/null +++ b/src/test/scala/chiselTests/InlineSpec.scala @@ -0,0 +1,57 @@ +// See LICENSE for license details. + +package chiselTests + +import chisel3._ +import chisel3.util.experimental.InlineInstance +import chisel3.internal.firrtl.Circuit +import firrtl.FirrtlExecutionSuccess +import firrtl.passes.InlineAnnotation +import firrtl.annotations.Annotation +import firrtl.analyses.InstanceGraph +import firrtl.{ir => fir} +import firrtl.WDefInstance +import firrtl.Mappers._ +import org.scalatest.{FreeSpec, Matchers} + +class InlineSpec extends FreeSpec with ChiselRunners with Matchers { + + trait Internals { this: Module => + val io = IO(new Bundle{ val a = Input(Bool()) }) + } + class Sub extends Module with Internals + trait HasSub { this: Module with Internals => + val sub = Module(new Sub) + sub.io.a := io.a + } + + class Foo extends Module with Internals with InlineInstance with HasSub + class Bar extends Module with Internals with HasSub + class Baz extends Module with Internals with HasSub + class Qux extends Module with Internals with HasSub + + def collectInstances(c: fir.Circuit, top: Option[String] = None): Seq[String] = new InstanceGraph(c) + .fullHierarchy.values.flatten.toSeq + .map( v => (top.getOrElse(v.head.name) +: v.tail.map(_.name)).mkString(".") ) + + "Module Inlining" - { + class Top extends Module with Internals { + val x = Module(new Foo) + val y = Module(new Bar with InlineInstance) + val z = Module(new Bar) + Seq(x, y, z).map(_.io.a := io.a) + } + "should compile to low FIRRTL" - { + Driver.execute(Array("-X", "low", "--target-dir", "test_run_dir"), () => new Top) match { + case ChiselExecutionSuccess(Some(chiselCircuit), _, Some(firrtlResult: FirrtlExecutionSuccess)) => + "emitting TWO InlineAnnotation at the CHIRRTL level" in { + chiselCircuit.annotations.map(_.toFirrtl).collect{ case a: InlineAnnotation => a }.size should be (2) + } + "low FIRRTL should contain only instance z" in { + val instances = collectInstances(firrtlResult.circuitState.circuit, Some("Top")).toSet + Set("Top", "Top.x$sub", "Top.y$sub", "Top.z", "Top.z.sub") should be (instances) + } + } + } + } +} -- cgit v1.2.3 From 87551bf5f56d52198efaabdeb69dcd15fb230954 Mon Sep 17 00:00:00 2001 From: Schuyler Eldridge Date: Tue, 21 Aug 2018 14:32:13 -0400 Subject: Add FlattenInstance API This adds a new trait, FlattenInstance, to chisel3.util.experimental. When mixed into a module or a specific instance this trait will "flatten", i.e., "inline that module and all of its submodules". This includes testing (additions to InlineSpec) and ScalaDoc documentation. Signed-off-by: Schuyler Eldridge --- .../scala/chisel3/util/experimental/Inline.scala | 35 ++++++++++++++++++++++ src/test/scala/chiselTests/InlineSpec.scala | 22 +++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/main/scala/chisel3/util/experimental/Inline.scala b/src/main/scala/chisel3/util/experimental/Inline.scala index 4039f3ed..8ec5219b 100644 --- a/src/main/scala/chisel3/util/experimental/Inline.scala +++ b/src/main/scala/chisel3/util/experimental/Inline.scala @@ -48,3 +48,38 @@ trait InlineInstance { self: BaseModule => def toFirrtl: Annotation = NoDedupAnnotation(self.toNamed) }) .map(chisel3.experimental.annotate(_)) } + +/** Flattens an instance of a module + * + * @example {{{ + * trait Internals { this: Module => + * val io = IO(new Bundle{ val a = Input(Bool()) }) + * } + * class Foo extends Module with Internals with FlattenInstance + * class Bar extends Module with Internals { + * val baz = Module(new Baz) + * baz.io.a := io.a + * } + * class Baz extends Module with Internals + * /* The resulting instances will be: + * - Top + * - Top.x + * - Top.y + * - Top.z + * - Top.z.baz */ + * class Top extends Module with Internals { + * val x = Module(new Foo) // x will be flattened + * val y = Module(new Bar with FlattenInstance) // y will also be flattened + * val z = Module(new Bar) // z will not be flattened + * Seq(x, y, z).map(_.io.a := io.a) + * } + * }}} + */ +trait FlattenInstance { self: BaseModule => + Seq(new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl: Annotation = FlattenAnnotation(self.toNamed) + def transformClass: Class[_ <: Transform] = classOf[Flatten] }, + new ChiselAnnotation { + def toFirrtl: Annotation = NoDedupAnnotation(self.toNamed) }) + .map(chisel3.experimental.annotate(_)) +} diff --git a/src/test/scala/chiselTests/InlineSpec.scala b/src/test/scala/chiselTests/InlineSpec.scala index 4482d9ec..a2aabdb3 100644 --- a/src/test/scala/chiselTests/InlineSpec.scala +++ b/src/test/scala/chiselTests/InlineSpec.scala @@ -3,11 +3,12 @@ package chiselTests import chisel3._ -import chisel3.util.experimental.InlineInstance +import chisel3.util.experimental.{InlineInstance, FlattenInstance} import chisel3.internal.firrtl.Circuit import firrtl.FirrtlExecutionSuccess import firrtl.passes.InlineAnnotation import firrtl.annotations.Annotation +import firrtl.transforms.FlattenAnnotation import firrtl.analyses.InstanceGraph import firrtl.{ir => fir} import firrtl.WDefInstance @@ -54,4 +55,23 @@ class InlineSpec extends FreeSpec with ChiselRunners with Matchers { } } } + + "Module Flattening" - { + class Top extends Module with Internals { + val x = Module(new Qux with FlattenInstance) + x.io.a := io.a + } + "should compile to low FIRRTL" - { + Driver.execute(Array("-X", "low", "--target-dir", "test_run_dir"), () => new Top) match { + case ChiselExecutionSuccess(Some(chiselCircuit), chirrtl, Some(firrtlResult: FirrtlExecutionSuccess)) => + "emitting ONE FlattenAnnotation at the CHIRRTL level" in { + chiselCircuit.annotations.map(_.toFirrtl).collect{ case a: FlattenAnnotation => a }.size should be (1) + } + "low FIRRTL should contain instance x only" in { + val instances = collectInstances(firrtlResult.circuitState.circuit, Some("Top")).toSet + Set("Top", "Top.x") should be (instances) + } + } + } + } } -- cgit v1.2.3