From 980778b1874b93b7e2778eb0c8f666f9691176f1 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 20 Jun 2018 17:09:48 -0700 Subject: Programmatic Port Creation (#833) Add chisel3.experimental.IO for programmatic port creation in Raw and MultiIOModules. suggestName is required to name ports that cannot be named by reflection. Two ports cannot be given the same name.--- .../src/main/scala/chisel3/core/Module.scala | 56 +++++++++++++++------- 1 file changed, 40 insertions(+), 16 deletions(-) (limited to 'chiselFrontend/src/main/scala/chisel3/core/Module.scala') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala index 2f365dd7..c4a48fb4 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala @@ -79,6 +79,40 @@ object Module { def currentModule: Option[BaseModule] = Builder.currentModule } +object IO { + /** Constructs a port for the current Module + * + * This must wrap the datatype used to set the io field of any Module. + * i.e. All concrete modules must have defined io in this form: + * [lazy] val io[: io type] = IO(...[: io type]) + * + * Items in [] are optional. + * + * The granted iodef must be a chisel type and not be bound to hardware. + * + * Also registers a Data as a port, also performing bindings. Cannot be called once ports are + * requested (so that all calls to ports will return the same information). + * Internal API. + */ + def apply[T<:Data](iodef: T): T = { + val module = Module.currentModule.get // Impossible to fail + require(!module.isClosed, "Can't add more ports after module close") + requireIsChiselType(iodef, "io type") + + // Clone the IO so we preserve immutability of data types + val iodefClone = try { + iodef.cloneTypeFull + } catch { + // For now this is going to be just a deprecation so we don't suddenly break everyone's code + case e: AutoClonetypeException => + Builder.deprecated(e.getMessage, Some(s"${iodef.getClass}")) + iodef + } + module.bindIoInPlace(iodefClone) + iodefClone + } +} + /** Abstract base class for Modules, an instantiable organizational unit for RTL. */ // TODO: seal this? @@ -99,6 +133,9 @@ abstract class BaseModule extends HasId { // protected var _closed = false + /** Internal check if a Module is closed */ + private[core] def isClosed = _closed + // Fresh Namespace because in Firrtl, Modules namespaces are disjoint with the global namespace private[core] val _namespace = Namespace.empty private val _ids = ArrayBuffer[HasId]() @@ -243,6 +280,8 @@ abstract class BaseModule extends HasId { iodef.bind(PortBinding(this)) _ports += iodef } + /** Private accessor for _bindIoInPlace */ + private[core] def bindIoInPlace(iodef: Data): Unit = _bindIoInPlace(iodef) /** * This must wrap the datatype used to set the io field of any Module. @@ -260,22 +299,7 @@ abstract class BaseModule extends HasId { * TODO(twigg): Specifically walk the Data definition to call out which nodes * are problematic. */ - protected def IO[T<:Data](iodef: T): T = { - require(!_closed, "Can't add more ports after module close") - requireIsChiselType(iodef, "io type") - - // Clone the IO so we preserve immutability of data types - val iodefClone = try { - iodef.cloneTypeFull - } catch { - // For now this is going to be just a deprecation so we don't suddenly break everyone's code - case e: AutoClonetypeException => - Builder.deprecated(e.getMessage, Some(s"${iodef.getClass}")) - iodef - } - _bindIoInPlace(iodefClone) - iodefClone - } + protected def IO[T<:Data](iodef: T): T = chisel3.core.IO.apply(iodef) // // Internal Functions -- cgit v1.2.3