summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam Izraelevitz2020-10-26 14:59:17 -0700
committerGitHub2020-10-26 21:59:17 +0000
commit1b6bd89dfafc774af1c926a982418294091f6346 (patch)
treec76739031286169fc04ab98936f9745f080fcdc6 /src
parent2d98132dfb849ef6c987ee5f49be596794887a08 (diff)
Bugfix - module name collision for injecting aspect (#1635)
* Bugfix - module name collision for injecting aspect * Fixed mechanism to avoid module name collisions * Added comments for reviewer feedback Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/aop/injecting/InjectingAspect.scala27
-rw-r--r--src/test/scala/chiselTests/aop/InjectionSpec.scala74
2 files changed, 69 insertions, 32 deletions
diff --git a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
index 747ba18d..8754f4e7 100644
--- a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
+++ b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
@@ -2,9 +2,9 @@
package chisel3.aop.injecting
-import chisel3.{Module, ModuleAspect, experimental, withClockAndReset, RawModule, MultiIOModule}
+import chisel3.{Module, ModuleAspect, MultiIOModule, RawModule, experimental, withClockAndReset}
import chisel3.aop._
-import chisel3.internal.Builder
+import chisel3.internal.{Builder, DynamicContext}
import chisel3.internal.firrtl.DefModule
import chisel3.stage.DesignAnnotation
import firrtl.annotations.ModuleTarget
@@ -42,17 +42,32 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule](
injection: M => Unit
) extends Aspect[T] {
final def toAnnotation(top: T): AnnotationSeq = {
- toAnnotation(selectRoots(top), top.name)
+ val moduleNames = Select.collectDeep(top) { case i => i.name }.toSeq
+ toAnnotation(selectRoots(top), top.name, moduleNames)
}
- final def toAnnotation(modules: Iterable[M], circuit: String): AnnotationSeq = {
+ /** Returns annotations which contain all injection logic
+ *
+ * @param modules The modules to inject into
+ * @param circuit Top level circuit
+ * @param moduleNames The names of all existing modules in the original circuit, to avoid name collisions
+ * @return
+ */
+ final def toAnnotation(modules: Iterable[M], circuit: String, moduleNames: Seq[String]): AnnotationSeq = {
+ val dynamicContext = new DynamicContext()
+ // Add existing module names into the namespace. If injection logic instantiates new modules
+ // which would share the same name, they will get uniquified accordingly
+ moduleNames.foreach { n =>
+ dynamicContext.globalNamespace.name(n)
+ }
RunFirrtlTransformAnnotation(new InjectingTransform) +: modules.map { module =>
val (chiselIR, _) = Builder.build(Module(new ModuleAspect(module) {
module match {
case x: MultiIOModule => withClockAndReset(x.clock, x.reset) { injection(module) }
case x: RawModule => injection(module)
}
- }))
+ }), dynamicContext)
+
val comps = chiselIR.components.map {
case x: DefModule if x.name == module.name => x.copy(id = module)
case other => other
@@ -65,7 +80,7 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule](
case m: firrtl.ir.Module if m.name == module.name =>
stmts += m.body
Nil
- case other =>
+ case other: firrtl.ir.Module =>
Seq(other)
}
diff --git a/src/test/scala/chiselTests/aop/InjectionSpec.scala b/src/test/scala/chiselTests/aop/InjectionSpec.scala
index 3cb0d48b..60233f48 100644
--- a/src/test/scala/chiselTests/aop/InjectionSpec.scala
+++ b/src/test/scala/chiselTests/aop/InjectionSpec.scala
@@ -3,42 +3,46 @@
package chiselTests.aop
import chisel3.testers.{BasicTester, TesterDriver}
-import chiselTests.ChiselFlatSpec
+import chiselTests.{ChiselFlatSpec, Utils}
import chisel3._
import chisel3.aop.injecting.InjectingAspect
+import logger.{LogLevel, LogLevelAnnotation}
-class SubmoduleManipulationTester extends BasicTester {
- val moduleSubmoduleA = Module(new SubmoduleA)
-}
+object InjectionHierarchy {
-class SubmoduleA extends Module {
- val io = IO(new Bundle {
- val out = Output(Bool())
- })
- io.out := false.B
-}
+ class SubmoduleManipulationTester extends BasicTester {
+ val moduleSubmoduleA = Module(new SubmoduleA)
+ }
-class SubmoduleB extends Module {
- val io = IO(new Bundle {
- val in = Input(Bool())
- })
-}
+ class SubmoduleA extends Module {
+ val io = IO(new Bundle {
+ val out = Output(Bool())
+ })
+ io.out := false.B
+ }
-class AspectTester(results: Seq[Int]) extends BasicTester {
- val values = VecInit(results.map(_.U))
- val counter = RegInit(0.U(results.length.W))
- counter := counter + 1.U
- when(counter >= values.length.U) {
- stop()
- }.otherwise {
- when(reset.asBool() === false.B) {
- printf("values(%d) = %d\n", counter, values(counter))
- assert(counter === values(counter))
+ class SubmoduleB extends Module {
+ val io = IO(new Bundle {
+ val in = Input(Bool())
+ })
+ }
+
+ class AspectTester(results: Seq[Int]) extends BasicTester {
+ val values = VecInit(results.map(_.U))
+ val counter = RegInit(0.U(results.length.W))
+ counter := counter + 1.U
+ when(counter >= values.length.U) {
+ stop()
+ }.otherwise {
+ when(reset.asBool() === false.B) {
+ assert(counter === values(counter))
+ }
}
}
}
-class InjectionSpec extends ChiselFlatSpec {
+class InjectionSpec extends ChiselFlatSpec with Utils {
+ import InjectionHierarchy._
val correctValueAspect = InjectingAspect(
{dut: AspectTester => Seq(dut)},
{dut: AspectTester =>
@@ -67,6 +71,16 @@ class InjectionSpec extends ChiselFlatSpec {
}
)
+ val duplicateSubmoduleAspect = InjectingAspect(
+ {dut: SubmoduleManipulationTester => Seq(dut)},
+ {_: SubmoduleManipulationTester =>
+ // By creating a second SubmoduleA, the module names would conflict unless they were uniquified
+ val moduleSubmoduleA2 = Module(new SubmoduleA)
+ //if we're here then we've elaborated correctly
+ stop()
+ }
+ )
+
"Test" should "pass if inserted the correct values" in {
assertTesterPasses{ new AspectTester(Seq(0, 1, 2)) }
}
@@ -88,4 +102,12 @@ class InjectionSpec extends ChiselFlatSpec {
"Test" should "pass if the submodules in SubmoduleManipulationTester can be manipulated by manipulateSubmoduleAspect" in {
assertTesterPasses({ new SubmoduleManipulationTester} , Nil, Seq(manipulateSubmoduleAspect) ++ TesterDriver.verilatorOnly)
}
+
+ "Module name collisions when adding a new module" should "be resolved" in {
+ assertTesterPasses(
+ { new SubmoduleManipulationTester},
+ Nil,
+ Seq(duplicateSubmoduleAspect) ++ TesterDriver.verilatorOnly
+ )
+ }
}