summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/RawModule.scala
diff options
context:
space:
mode:
authorJack Koenig2021-01-21 22:50:12 -0800
committerGitHub2021-01-21 22:50:12 -0800
commitdd6871b8b3f2619178c2a333d9d6083805d99e16 (patch)
tree825776855e7d2fc28ef32ebb05df7339c24e00b3 /core/src/main/scala/chisel3/RawModule.scala
parent616256c35cb7de8fcd97df56af1986b747abe54d (diff)
parent53c24cb0a369d4c4f57c28c098b30e4d3640eac2 (diff)
Merge pull request #1745 from chipsalliance/remove-val-io
Remove "val io" and rename MultiIOModule to Module
Diffstat (limited to 'core/src/main/scala/chisel3/RawModule.scala')
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala157
1 files changed, 85 insertions, 72 deletions
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index 9f0a24d6..0adacedb 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
@@ -142,86 +143,83 @@ 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
+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
+ }
+ }
- super.initializeInParent(parentCompileOptions)
- clock := Builder.forcedClock
- reset := Builder.forcedReset
+ 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(...)."
+ ))
}
-}
-
-package internal {
/** 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.
+ * '''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 MultiIOModule {
- // These are to be phased out
- protected var override_clock: Option[Clock] = None
- protected var override_reset: Option[Bool] = None
-
- // 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
+ 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)
// 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
@@ -234,17 +232,32 @@ 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))
+ override def _compatAutoWrapPorts(): Unit = {
+ if (!_compatIoPortBound() && _io != null) {
+ _bindIoInPlace(_io)
}
+ }
+ }
- clock := override_clock.getOrElse(Builder.forcedClock)
- reset := override_reset.getOrElse(Builder.forcedReset)
+ import chisel3.experimental.Param
+
+ /** Legacy BlackBox class will reflectively autowrap val io
+ *
+ * '''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])
+ (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)
+ }
}
}
}