From 5ece5aa8ac2716d66a6ed91e38a978049d8bf250 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 20 Jan 2021 13:46:48 -0800 Subject: Rename MultiIOModule to Module --- core/src/main/scala/chisel3/RawModule.scala | 57 ++--------------------------- 1 file changed, 3 insertions(+), 54 deletions(-) (limited to 'core/src/main/scala/chisel3/RawModule.scala') diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index 9f0a24d6..bb84c444 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -142,47 +142,14 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) } } -trait RequireAsyncReset extends MultiIOModule { +trait RequireAsyncReset extends Module { override private[chisel3] def mkReset: AsyncReset = AsyncReset() } -trait RequireSyncReset extends MultiIOModule { +trait RequireSyncReset extends Module { override private[chisel3] def mkReset: Bool = Bool() } -/** Abstract base class for Modules, which behave much like Verilog modules. - * These may contain both logic and state which are written in the Module - * body (constructor). - * This abstract base class includes an implicit clock and reset. - * - * @note Module instantiations must be wrapped in a Module() call. - */ -abstract class MultiIOModule(implicit moduleCompileOptions: CompileOptions) - extends RawModule { - // Implicit clock and reset pins - final val clock: Clock = IO(Input(Clock())).autoSeed("clock") - final val reset: Reset = IO(Input(mkReset)).autoSeed("reset") - - private[chisel3] def mkReset: Reset = { - // Top module and compatibility mode use Bool for reset - val inferReset = _parent.isDefined && moduleCompileOptions.inferModuleReset - if (inferReset) Reset() else Bool() - } - - // Setup ClockAndReset - Builder.currentClock = Some(clock) - Builder.currentReset = Some(reset) - Builder.clearPrefix() - - private[chisel3] override def initializeInParent(parentCompileOptions: CompileOptions): Unit = { - implicit val sourceInfo = UnlocatableSourceInfo - - super.initializeInParent(parentCompileOptions) - clock := Builder.forcedClock - reset := Builder.forcedReset - } -} - package internal { /** Legacy Module class that restricts IOs to just io, clock, and reset, and provides a constructor @@ -192,12 +159,7 @@ package internal { * IO), the clock and reset constructors will be phased out. Recommendation is to wrap the module * in a withClock/withReset/withClockAndReset block, or directly hook up clock or reset IO pins. */ - abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions) - extends MultiIOModule { - // These are to be phased out - protected var override_clock: Option[Clock] = None - protected var override_reset: Option[Bool] = None - + abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions) extends Module { // IO for this Module. At the Scala level (pre-FIRRTL transformations), // connections in and out of a Module may only go through `io` elements. @deprecated("Removed for causing issues in Scala 2.12+. You remain free to define io Bundles " + @@ -233,18 +195,5 @@ package internal { super.generateComponent() } - - private[chisel3] override def initializeInParent(parentCompileOptions: 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 (!parentCompileOptions.explicitInvalidate) { - pushCommand(DefInvalid(sourceInfo, _io.ref)) - } - - clock := override_clock.getOrElse(Builder.forcedClock) - reset := override_reset.getOrElse(Builder.forcedReset) - } } } -- cgit v1.2.3 From 8a73362bb6fe87817a1867cc2482c1841f95c077 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 20 Jan 2021 18:55:16 -0800 Subject: Remove val io Chisel projects no longer need -Xsource:2.11 when compiling with Scala 2.12. Autowrapping of "val io" for compatibility mode Modules is now implemented using reflection instead of calling the virtual method. Also move Chisel.BlackBox to new chisel3.internal.LegacyBlackBox --- core/src/main/scala/chisel3/RawModule.scala | 99 ++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 24 deletions(-) (limited to 'core/src/main/scala/chisel3/RawModule.scala') diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index bb84c444..ac6a2d1f 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -3,6 +3,7 @@ package chisel3 import scala.collection.mutable.{ArrayBuffer, HashMap} +import scala.util.Try import scala.collection.JavaConversions._ import scala.language.experimental.macros @@ -150,40 +151,62 @@ trait RequireSyncReset extends Module { override private[chisel3] def mkReset: Bool = Bool() } -package internal { +package object internal { + + // Private reflective version of "val io" to maintain Chisel.Module semantics without having + // io as a virtual method. See https://github.com/freechipsproject/chisel3/pull/1550 for more + // information about the removal of "val io" + private def reflectivelyFindValIO(self: BaseModule): Record = { + // Java reflection is faster and works for the common case + def tryJavaReflect: Option[Record] = Try { + self.getClass.getMethod("io").invoke(self).asInstanceOf[Record] + }.toOption + // Anonymous subclasses don't work with Java reflection, so try slower, Scala reflection + def tryScalaReflect: Option[Record] = { + val ru = scala.reflect.runtime.universe + import ru.{Try => _, _} + val m = ru.runtimeMirror(self.getClass.getClassLoader) + val im = m.reflect(self) + val tpe = im.symbol.toType + // For some reason, in anonymous subclasses, looking up the Term by name (TermName("io")) + // hits an internal exception. Searching for the term seems to work though so we use that. + val ioTerm: Option[TermSymbol] = tpe.decls.collectFirst { + case d if d.name.toString == "io" && d.isTerm => d.asTerm + } + ioTerm.flatMap { term => + Try { + im.reflectField(term).get.asInstanceOf[Record] + }.toOption + } + } + + tryJavaReflect + .orElse(tryScalaReflect) + .map(_.autoSeed("io")) + .orElse { + // Fallback if reflection fails, user can wrap in IO(...) + self.findPort("io") + .collect { case r: Record => r } + }.getOrElse(throwException( + s"Compatibility mode Module '$this' must have a 'val io' Bundle. " + + "If there is such a field and you still see this error, autowrapping has failed (sorry!). " + + "Please wrap the Bundle declaration in IO(...)." + )) + } /** Legacy Module class that restricts IOs to just io, clock, and reset, and provides a constructor * for threading through explicit clock and reset. * - * While this class isn't planned to be removed anytime soon (there are benefits to restricting - * IO), the clock and reset constructors will be phased out. Recommendation is to wrap the module - * in a withClock/withReset/withClockAndReset block, or directly hook up clock or reset IO pins. + * This is only intended as a bridge from chisel3 to Chisel.Module, do not extend this in user + * code, use [[Module]] */ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions) extends Module { - // IO for this Module. At the Scala level (pre-FIRRTL transformations), - // connections in and out of a Module may only go through `io` elements. - @deprecated("Removed for causing issues in Scala 2.12+. You remain free to define io Bundles " + - "in your Modules, but you cannot rely on an io field in every Module. " + - "For more information, see: https://github.com/freechipsproject/chisel3/pull/1550.", - "Chisel 3.4" - ) - def io: Record - - // Private accessor to reduce number of deprecation warnings - private[chisel3] def _io: Record = io + + private lazy val _io: Record = reflectivelyFindValIO(this) // Allow access to bindings from the compatibility package protected def _compatIoPortBound() = portsContains(_io) - private[chisel3] override def namePorts(names: HashMap[HasId, String]): Unit = { - for (port <- getModulePorts) { - // This should already have been caught - if (!names.contains(port)) throwException(s"Unable to name port $port in $this") - val name = names(port) - port.setRef(ModuleIO(this, _namespace.name(name))) - } - } - private[chisel3] override def generateComponent(): Component = { _compatAutoWrapPorts() // pre-IO(...) compatibility hack @@ -195,5 +218,33 @@ package internal { super.generateComponent() } + + override def _compatAutoWrapPorts(): Unit = { + if (!_compatIoPortBound() && _io != null) { + _bindIoInPlace(_io) + } + } + } + + import chisel3.experimental.Param + + /** Legacy BlackBox class will reflectively autowrap val io + * + * '''Do not use this class in user code'''. Use whichever `Module` is imported by your wildcard + * import (preferably `import chisel3._`). + */ + abstract class LegacyBlackBox(params: Map[String, Param] = Map.empty[String, Param]) + (implicit moduleCompileOptions: CompileOptions) + extends chisel3.BlackBox(params) { + + override private[chisel3] lazy val _io: Record = reflectivelyFindValIO(this) + + // This class auto-wraps the BlackBox with IO(...), allowing legacy code (where IO(...) wasn't + // required) to build. + override def _compatAutoWrapPorts(): Unit = { + if (!_compatIoPortBound()) { + _bindIoInPlace(_io) + } + } } } -- cgit v1.2.3 From 6c6ec7161e8f046fff1cfc68a468ce2f053fdb7f Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 21 Jan 2021 11:41:20 -0800 Subject: Fold Chisel.CompatibilityModule into chisel3.internal.LegacyModule --- core/src/main/scala/chisel3/RawModule.scala | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'core/src/main/scala/chisel3/RawModule.scala') diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index ac6a2d1f..a686fd7e 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -197,10 +197,23 @@ package object internal { /** Legacy Module class that restricts IOs to just io, clock, and reset, and provides a constructor * for threading through explicit clock and reset. * - * This is only intended as a bridge from chisel3 to Chisel.Module, do not extend this in user - * code, use [[Module]] + * '''Do not use this class in user code'''. Use whichever `Module` is imported by your wildcard + * import (preferably `import chisel3._`). */ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions) extends Module { + // Provide a non-deprecated constructor + def this(override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) + (implicit moduleCompileOptions: CompileOptions) = { + this() + this.override_clock = override_clock + this.override_reset = override_reset + } + def this(_clock: Clock)(implicit moduleCompileOptions: CompileOptions) = + this(Option(_clock), None)(moduleCompileOptions) + def this(_reset: Bool)(implicit moduleCompileOptions: CompileOptions) = + this(None, Option(_reset))(moduleCompileOptions) + def this(_clock: Clock, _reset: Bool)(implicit moduleCompileOptions: CompileOptions) = + this(Option(_clock), Option(_reset))(moduleCompileOptions) private lazy val _io: Record = reflectivelyFindValIO(this) -- cgit v1.2.3 From 53c24cb0a369d4c4f57c28c098b30e4d3640eac2 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 21 Jan 2021 20:31:39 -0800 Subject: Apply suggestions from code review Co-authored-by: Megan Wachs --- core/src/main/scala/chisel3/RawModule.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'core/src/main/scala/chisel3/RawModule.scala') diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index a686fd7e..0adacedb 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -202,7 +202,7 @@ package object internal { */ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions) extends Module { // Provide a non-deprecated constructor - def this(override_clock: Option[Clock]=None, override_reset: Option[Bool]=None) + def this(override_clock: Option[Clock] = None, override_reset: Option[Bool]=None) (implicit moduleCompileOptions: CompileOptions) = { this() this.override_clock = override_clock @@ -243,7 +243,7 @@ package object internal { /** Legacy BlackBox class will reflectively autowrap val io * - * '''Do not use this class in user code'''. Use whichever `Module` is imported by your wildcard + * '''Do not use this class in user code'''. Use whichever `BlackBox` is imported by your wildcard * import (preferably `import chisel3._`). */ abstract class LegacyBlackBox(params: Map[String, Param] = Map.empty[String, Param]) -- cgit v1.2.3