diff options
Diffstat (limited to 'core/src')
| -rw-r--r-- | core/src/main/scala/chisel3/Annotation.scala | 4 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/BlackBox.scala | 18 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/Module.scala | 62 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/RawModule.scala | 157 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/core/package.scala | 4 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/package.scala | 3 |
6 files changed, 156 insertions, 92 deletions
diff --git a/core/src/main/scala/chisel3/Annotation.scala b/core/src/main/scala/chisel3/Annotation.scala index c8ac462d..545ea480 100644 --- a/core/src/main/scala/chisel3/Annotation.scala +++ b/core/src/main/scala/chisel3/Annotation.scala @@ -4,7 +4,7 @@ package chisel3.experimental import scala.language.existentials import chisel3.internal.{Builder, InstanceId, LegacyModule} -import chisel3.{CompileOptions, Data} +import chisel3.{CompileOptions, Data, RawModule} import firrtl.Transform import firrtl.annotations._ import firrtl.options.Unserializable @@ -78,7 +78,7 @@ object doNotDedup { * @param module The module to be marked * @return Unmodified signal `module` */ - def apply[T <: LegacyModule](module: T)(implicit compileOptions: CompileOptions): Unit = { + def apply[T <: RawModule](module: T)(implicit compileOptions: CompileOptions): Unit = { annotate(new ChiselAnnotation { def toFirrtl = NoDedupAnnotation(module.toNamed) }) } } diff --git a/core/src/main/scala/chisel3/BlackBox.scala b/core/src/main/scala/chisel3/BlackBox.scala index 1b093ee1..03543790 100644 --- a/core/src/main/scala/chisel3/BlackBox.scala +++ b/core/src/main/scala/chisel3/BlackBox.scala @@ -134,15 +134,11 @@ package experimental { */ abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param])(implicit compileOptions: CompileOptions) extends BaseBlackBox { - @deprecated("Removed for causing issues in Scala 2.12+. You remain free to define io Bundles " + - "in your BlackBoxes, but you cannot rely on an io field in every BlackBox. " + - "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 + // Find a Record port named "io" for purposes of stripping the prefix + private[chisel3] lazy val _io: Record = + this.findPort("io") + .collect { case r: Record => r } // Must be a Record + .getOrElse(null) // null handling occurs in generateComponent // Allow access to bindings from the compatibility package protected def _compatIoPortBound() = portsContains(_io) @@ -151,9 +147,9 @@ abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param _compatAutoWrapPorts() // pre-IO(...) compatibility hack // Restrict IO to just io, clock, and reset - require(_io != null, "BlackBox must have io") + require(_io != null, "BlackBox must have a port named 'io' of type Record!") require(portsContains(_io), "BlackBox must have io wrapped in IO(...)") - require(portsSize == 1, "BlackBox must only have io as IO") + require(portsSize == 1, "BlackBox must only have one IO, called `io`") require(!_closed, "Can't generate module more than once") _closed = true diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index 236f528e..d34211f1 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -6,15 +6,14 @@ import scala.collection.immutable.ListMap import scala.collection.mutable.{ArrayBuffer, HashMap} import scala.collection.JavaConversions._ import scala.language.experimental.macros - import java.util.IdentityHashMap import chisel3.internal._ import chisel3.internal.Builder._ import chisel3.internal.firrtl._ -import chisel3.internal.sourceinfo.{InstTransform, SourceInfo} +import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo} import chisel3.experimental.BaseModule -import _root_.firrtl.annotations.{ModuleName, ModuleTarget, IsModule} +import _root_.firrtl.annotations.{IsModule, ModuleName, ModuleTarget} object Module extends SourceInfoDoc { /** A wrapper method that all Module instantiations must be wrapped in @@ -87,6 +86,56 @@ object Module extends SourceInfoDoc { def currentModule: Option[BaseModule] = Builder.currentModule } +/** 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 Module(implicit moduleCompileOptions: CompileOptions) extends RawModule { + // Implicit clock and reset pins + final val clock: Clock = IO(Input(Clock())).suggestName("clock") + final val reset: Reset = IO(Input(mkReset)).suggestName("reset") + + // TODO It's hard to remove these deprecated override methods because they're used by + // Chisel.QueueCompatibility which extends chisel3.Queue which extends chisel3.Module + private var _override_clock: Option[Clock] = None + private var _override_reset: Option[Bool] = None + @deprecated("Use withClock at Module instantiation", "Chisel 3.5") + protected def override_clock: Option[Clock] = _override_clock + @deprecated("Use withClock at Module instantiation", "Chisel 3.5") + protected def override_reset: Option[Bool] = _override_reset + @deprecated("Use withClock at Module instantiation", "Chisel 3.5") + protected def override_clock_=(rhs: Option[Clock]): Unit = { + _override_clock = rhs + } + @deprecated("Use withClock at Module instantiation", "Chisel 3.5") + protected def override_reset_=(rhs: Option[Bool]): Unit = { + _override_reset = rhs + } + + 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 := _override_clock.getOrElse(Builder.forcedClock) + reset := _override_reset.getOrElse(Builder.forcedReset) + } +} + + package experimental { object IO { @@ -145,7 +194,7 @@ package internal { if (!compileOptions.explicitInvalidate) { pushCommand(DefInvalid(sourceInfo, clonePorts.ref)) } - if (proto.isInstanceOf[MultiIOModule]) { + if (proto.isInstanceOf[Module]) { clonePorts("clock") := Module.clock clonePorts("reset") := Module.reset } @@ -208,6 +257,11 @@ package experimental { // mainly for compatibility purposes. protected def portsContains(elem: Data): Boolean = _ports contains elem + // This is dangerous because it can be called before the module is closed and thus there could + // be more ports and names have not yet been finalized. + // This should only to be used during the process of closing when it is safe to do so. + private[chisel3] def findPort(name: String): Option[Data] = _ports.find(_.seedOpt.contains(name)) + protected def portsSize: Int = _ports.size /** Generates the FIRRTL Component (Module or Blackbox) of this Module. 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) + } } } } diff --git a/core/src/main/scala/chisel3/core/package.scala b/core/src/main/scala/chisel3/core/package.scala index 1da4ba97..fa29f244 100644 --- a/core/src/main/scala/chisel3/core/package.scala +++ b/core/src/main/scala/chisel3/core/package.scala @@ -66,13 +66,13 @@ package object core { type RawModule = chisel3.RawModule @deprecated("Avoid importing from chisel3.core, these are not public APIs and may change at any time. " + "Use chisel3.MultiIOModule instead. This alias will be removed in 3.4.", "since the beginning of time") - type MultiIOModule = chisel3.MultiIOModule + type MultiIOModule = chisel3.Module @deprecated("Avoid importing from chisel3.core, these are not public APIs and may change at any time. " + " Use chisel3.RawModule instead. This alias will be removed in 3.4.", "since the beginning of time") type UserModule = chisel3.RawModule @deprecated("Avoid importing from chisel3.core, these are not public APIs and may change at any time. " + "Use chisel3.MultiIOModule instead. This alias will be removed in 3.4.", "since the beginning of time") - type ImplicitModule = chisel3.MultiIOModule + type ImplicitModule = chisel3.Module @deprecated("Use the version in chisel3._", "3.2") val Bits = chisel3.Bits diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala index fb83c9d9..d5a4bfae 100644 --- a/core/src/main/scala/chisel3/package.scala +++ b/core/src/main/scala/chisel3/package.scala @@ -167,7 +167,8 @@ package object chisel3 { type InstanceId = internal.InstanceId - type Module = chisel3.internal.LegacyModule + @deprecated("MultiIOModule is now just Module", "Chisel 3.5") + type MultiIOModule = chisel3.Module /** Implicit for custom Printable string interpolator */ implicit class PrintableHelper(val sc: StringContext) extends AnyVal { |
