From d02a8605335bf57557260f18ce0454f66f454a4d Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 20 Dec 2017 12:41:58 -0800 Subject: [PATCH] Add compileOptions to Module.apply, use for invalidating submod ports Fixes #746 Also add test for https://github.com/freechipsproject/firrtl/issues/705 --- .../main/scala/chisel3/core/BlackBox.scala | 4 ++-- .../src/main/scala/chisel3/core/Module.scala | 8 ++++--- .../main/scala/chisel3/core/UserModule.scala | 23 +++++++++++-------- .../sourceinfo/SourceInfoTransform.scala | 2 +- .../CompatibilityInteroperabilitySpec.scala | 22 ++++++++++++++++++ src/test/scala/chiselTests/Util.scala | 22 ++++++++++++++++++ src/test/scala/chiselTests/Vec.scala | 11 +-------- src/test/scala/chiselTests/When.scala | 20 ++++++++++++++++ 8 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 src/test/scala/chiselTests/Util.scala diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala index f5e0d5ba531..be6000c8550 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala @@ -80,7 +80,7 @@ abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Para component } - private[core] def initializeInParent() { + private[core] def initializeInParent(instanceCompileOptions: CompileOptions): Unit = { implicit val sourceInfo = UnlocatableSourceInfo for (x <- getModulePorts) { @@ -165,7 +165,7 @@ abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param component } - private[core] def initializeInParent() { + private[core] def initializeInParent(instanceCompileOptions: CompileOptions): Unit = { for ((_, port) <- io.elements) { pushCommand(DefInvalid(UnlocatableSourceInfo, port.ref)) } diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 0e919d3c776..a51108e00c5 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -23,7 +23,9 @@ object Module { */ def apply[T <: BaseModule](bc: => T): T = macro InstTransform.apply[T] - def do_apply[T <: BaseModule](bc: => T)(implicit sourceInfo: SourceInfo): T = { + def do_apply[T <: BaseModule](bc: => T) + (implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions): T = { if (Builder.readyForModuleConstr) { throwException("Error: Called Module() twice without instantiating a Module." + sourceInfo.makeMessage(" See " + _)) @@ -62,7 +64,7 @@ object Module { // Handle connections at enclosing scope if(!Builder.currentModule.isEmpty) { pushCommand(DefInstance(sourceInfo, module, component.ports)) - module.initializeInParent() + module.initializeInParent(compileOptions) } module } @@ -124,7 +126,7 @@ abstract class BaseModule extends HasId { /** Sets up this module in the parent context */ - private[core] def initializeInParent() + private[core] def initializeInParent(instanceCompileOptions: CompileOptions): Unit // // Chisel Internals diff --git a/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala b/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala index c99d53cf141..3ea098ba8c3 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala @@ -81,8 +81,15 @@ abstract class UserModule(implicit moduleCompileOptions: CompileOptions) component } - // There is no initialization to be done by default. - private[core] def initializeInParent() {} + private[core] def initializeInParent(instanceCompileOptions: CompileOptions): Unit = { + implicit val sourceInfo = UnlocatableSourceInfo + + if (!instanceCompileOptions.explicitInvalidate) { + for (port <- getModulePorts) { + pushCommand(DefInvalid(sourceInfo, port.ref)) + } + } + } } /** Abstract base class for Modules, which behave much like Verilog modules. @@ -100,14 +107,10 @@ abstract class ImplicitModule(implicit moduleCompileOptions: CompileOptions) // Setup ClockAndReset Builder.currentClockAndReset = Some(ClockAndReset(clock, reset)) - private[core] override def initializeInParent() { + private[core] override def initializeInParent(instanceCompileOptions: CompileOptions): Unit = { implicit val sourceInfo = UnlocatableSourceInfo - if (!compileOptions.explicitInvalidate) { - for (port <- getModulePorts) { - pushCommand(DefInvalid(sourceInfo, port.ref)) - } - } + super.initializeInParent(instanceCompileOptions) clock := Builder.forcedClock reset := Builder.forcedReset } @@ -173,12 +176,12 @@ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions) super.generateComponent() } - private[core] override def initializeInParent() { + private[core] override def initializeInParent(instanceCompileOptions: CompileOptions): Unit = { // Don't generate source info referencing parents inside a module, since this interferes with // module de-duplication in FIRRTL emission. implicit val sourceInfo = UnlocatableSourceInfo - if (!compileOptions.explicitInvalidate) { + if (!instanceCompileOptions.explicitInvalidate) { pushCommand(DefInvalid(sourceInfo, io.ref)) } diff --git a/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala b/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala index 47c77c98e43..9f3ac88d56e 100644 --- a/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala +++ b/coreMacros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala @@ -38,7 +38,7 @@ class UIntTransform(val c: Context) extends SourceInfoTransformMacro { class InstTransform(val c: Context) extends SourceInfoTransformMacro { import c.universe._ def apply[T: c.WeakTypeTag](bc: c.Tree): c.Tree = { - q"$thisObj.do_apply($bc)($implicitSourceInfo)" + q"$thisObj.do_apply($bc)($implicitSourceInfo, $implicitCompileOptions)" } } diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala index c0538123da1..457f26def07 100644 --- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala +++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala @@ -217,5 +217,27 @@ class CompatibiltyInteroperabilitySpec extends ChiselFlatSpec { stop() }) } + + "An instance of a chisel3.Module inside a Chisel.Module" should "have its inputs invalidated" in { + compile { + import Chisel._ + new Module { + val io = new Bundle { + val in = UInt(INPUT, width = 32) + val cond = Bool(INPUT) + val out = UInt(OUTPUT, width = 32) + } + val children = Seq(Module(new PassthroughModule), + Module(new PassthroughMultiIOModule), + Module(new PassthroughRawModule)) + io.out := children.map(_.io.out).reduce(_ + _) + children.foreach { child => + when (io.cond) { + child.io.in := io.in + } + } + } + } + } } diff --git a/src/test/scala/chiselTests/Util.scala b/src/test/scala/chiselTests/Util.scala new file mode 100644 index 00000000000..80e37285a55 --- /dev/null +++ b/src/test/scala/chiselTests/Util.scala @@ -0,0 +1,22 @@ +// Useful utilities for tests + +package chiselTests + +import chisel3._ +import chisel3.experimental._ + +class PassthroughModuleIO extends Bundle { + val in = Input(UInt(32.W)) + val out = Output(UInt(32.W)) +} + +trait AbstractPassthroughModule extends RawModule { + val io = IO(new PassthroughModuleIO) + io.out := io.in +} + +class PassthroughModule extends Module with AbstractPassthroughModule +class PassthroughMultiIOModule extends MultiIOModule with AbstractPassthroughModule +class PassthroughRawModule extends RawModule with AbstractPassthroughModule + + diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala index 08b9cdf5fa2..bf25ed8233f 100644 --- a/src/test/scala/chiselTests/Vec.scala +++ b/src/test/scala/chiselTests/Vec.scala @@ -3,6 +3,7 @@ package chiselTests import chisel3._ +import chisel3.experimental.RawModule import chisel3.core.Binding.BindingException import chisel3.testers.BasicTester import chisel3.util._ @@ -153,16 +154,6 @@ class ZeroEntryVecTester extends BasicTester { stop() } -class PassthroughModuleIO extends Bundle { - val in = Input(UInt(32.W)) - val out = Output(UInt(32.W)) -} - -class PassthroughModule extends Module { - val io = IO(new PassthroughModuleIO) - io.out := io.in -} - class PassthroughModuleTester extends Module { val io = IO(Flipped(new PassthroughModuleIO)) // This drives the input of a PassthroughModule diff --git a/src/test/scala/chiselTests/When.scala b/src/test/scala/chiselTests/When.scala index 3bd63831596..a1a7afb7b4d 100644 --- a/src/test/scala/chiselTests/When.scala +++ b/src/test/scala/chiselTests/When.scala @@ -76,6 +76,23 @@ class NoOtherwiseOverlappedWhenTester() extends BasicTester { } } +class SubmoduleWhenTester extends BasicTester { + val (cycle, done) = Counter(true.B, 3) + when (done) { stop() } + val children = Seq(Module(new PassthroughModule), + Module(new PassthroughMultiIOModule), + Module(new PassthroughRawModule)) + children.foreach { child => + when (cycle === 1.U) { + child.io.in := "hdeadbeef".U + assert(child.io.out === "hdeadbeef".U) + } .otherwise { + child.io.in := "h0badcad0".U + assert(child.io.out === "h0badcad0".U) + } + } +} + class WhenSpec extends ChiselFlatSpec { "When, elsewhen, and otherwise with orthogonal conditions" should "work" in { assertTesterPasses{ new WhenTester } @@ -86,4 +103,7 @@ class WhenSpec extends ChiselFlatSpec { "When and elsewhen without otherwise with overlapped conditions" should "work" in { assertTesterPasses{ new NoOtherwiseOverlappedWhenTester } } + "Conditional connections to submodule ports" should "be handled properly" in { + assertTesterPasses(new SubmoduleWhenTester) + } }