summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/core/Module.scala
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/core/Module.scala')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Module.scala292
1 files changed, 142 insertions, 150 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
index b838eb05..4c4c0c01 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
@@ -2,13 +2,16 @@
package chisel3.core
-import scala.collection.mutable.ArrayBuffer
+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.firrtl.{Command => _, _}
-import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo}
+import chisel3.internal.sourceinfo.{InstTransform, SourceInfo}
object Module {
/** A wrapper method that all Module instantiations must be wrapped in
@@ -18,19 +21,16 @@ object Module {
*
* @return the input module `m` with Chisel metadata properly set
*/
- def apply[T <: Module](bc: => T): T = macro InstTransform.apply[T]
-
- def do_apply[T <: Module](bc: => T)(implicit sourceInfo: SourceInfo): T = {
- // Don't generate source info referencing parents inside a module, sincce this interferes with
- // module de-duplication in FIRRTL emission.
- val childSourceInfo = UnlocatableSourceInfo
+ def apply[T <: BaseModule](bc: => T): T = macro InstTransform.apply[T]
+ def do_apply[T <: BaseModule](bc: => T)(implicit sourceInfo: SourceInfo): T = {
if (Builder.readyForModuleConstr) {
throwException("Error: Called Module() twice without instantiating a Module." +
sourceInfo.makeMessage(" See " + _))
}
Builder.readyForModuleConstr = true
- val parent: Option[Module] = Builder.currentModule
+
+ val parent = Builder.currentModule
val whenDepth: Int = Builder.whenDepth
val clockAndReset: Option[ClockAndReset] = Builder.currentClockAndReset
@@ -39,8 +39,7 @@ object Module {
// - unset readyForModuleConstr
// - reset whenDepth to 0
// - set currentClockAndReset
- val m = bc.setRefs()
- m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs
+ val module: T = bc // bc is actually evaluated here
if (Builder.whenDepth != 0) {
throwException("Internal Error! When depth is != 0, this should not be possible")
@@ -54,23 +53,15 @@ object Module {
Builder.whenDepth = whenDepth
Builder.currentClockAndReset = clockAndReset // Back to clock and reset scope
- val ports = m.computePorts
- // Blackbox inherits from Module so we have to match on it first TODO fix
- val component = m match {
- case bb: BlackBox =>
- DefBlackBox(bb, bb.name, ports, bb.params)
- case mod: Module =>
- mod._commands.prepend(DefInvalid(childSourceInfo, mod.io.ref)) // init module outputs
- DefModule(mod, mod.name, ports, mod._commands)
- }
- m._component = Some(component)
+ val component = module.generateComponent()
Builder.components += component
- // Avoid referencing 'parent' in top module
+
+ // Handle connections at enclosing scope
if(!Builder.currentModule.isEmpty) {
- pushCommand(DefInstance(sourceInfo, m, ports))
- m.setupInParent(childSourceInfo)
+ pushCommand(DefInstance(sourceInfo, module, component.ports))
+ module.initializeInParent()
}
- m
+ module
}
/** Returns the implicit Clock */
@@ -79,141 +70,94 @@ object Module {
def reset: Bool = Builder.forcedReset
}
-/** 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).
- *
- * @note Module instantiations must be wrapped in a Module() call.
+/** Abstract base class for Modules, an instantiable organizational unit for RTL.
*/
-abstract class Module(
- override_clock: Option[Clock]=None, override_reset: Option[Bool]=None)
- (implicit moduleCompileOptions: CompileOptions)
-extends HasId {
- // _clock and _reset can be clock and reset in these 2ary constructors
- // once chisel2 compatibility issues are resolved
- 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)
-
- // This function binds the iodef as a port in the hardware graph
- private[chisel3] def Port[T<:Data](iodef: T): iodef.type = {
- // Bind each element of the iodef to being a Port
- Binding.bind(iodef, PortBinder(this), "Error: iodef")
- iodef
- }
-
- def annotate(annotation: ChiselAnnotation): Unit = {
- Builder.annotations += annotation
+// TODO: seal this?
+abstract class BaseModule extends HasId {
+ //
+ // Builder Internals - this tracks which Module RTL construction belongs to.
+ //
+ if (!Builder.readyForModuleConstr) {
+ throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
}
+ readyForModuleConstr = false
- private[core] var ioDefined: Boolean = false
-
- /**
- * 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 WILL NOT be cloned (to allow for more seamless use of
- * anonymous Bundles in the IO) and thus CANNOT have been bound to any logic.
- * This will error if any node is bound (e.g. due to logic in a Bundle
- * constructor, which is considered improper).
- *
- * TODO(twigg): Specifically walk the Data definition to call out which nodes
- * are problematic.
- */
- def IO[T<:Data](iodef: T): iodef.type = {
- require(!ioDefined, "Another IO definition for this module was already declared!")
- ioDefined = true
+ Builder.currentModule = Some(this)
+ Builder.whenDepth = 0
- Port(iodef)
- }
+ //
+ // Module Construction Internals
+ //
+ protected var _closed = false
// Fresh Namespace because in Firrtl, Modules namespaces are disjoint with the global namespace
private[core] val _namespace = Namespace.empty
- private[chisel3] val _commands = ArrayBuffer[Command]()
- private[core] val _ids = ArrayBuffer[HasId]()
- Builder.currentModule = Some(this)
- Builder.whenDepth = 0
- if (!Builder.readyForModuleConstr) {
- throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
+ private val _ids = ArrayBuffer[HasId]()
+ private[chisel3] def addId(d: HasId) {
+ require(!_closed, "Can't write to module after module close")
+ _ids += d
+ }
+ protected def getIds = {
+ require(_closed, "Can't get ids before module close")
+ _ids.toSeq
}
- readyForModuleConstr = false
- /** Desired name of this module. */
+ private val _ports = new ArrayBuffer[Data]()
+ // getPorts unfortunately already used for tester compatibility
+ protected def getModulePorts = {
+ require(_closed, "Can't get ports before module close")
+ _ports.toSeq
+ }
+
+ // These methods allow checking some properties of ports before the module is closed,
+ // mainly for compatibility purposes.
+ protected def portsContains(elem: Data): Boolean = _ports contains elem
+ protected def portsSize: Int = _ports.size
+
+ /** Generates the FIRRTL Component (Module or Blackbox) of this Module.
+ * Also closes the module so no more construction can happen inside.
+ */
+ private[core] def generateComponent(): Component
+
+ /** Sets up this module in the parent context
+ */
+ private[core] def initializeInParent()
+
+ //
+ // Chisel Internals
+ //
+ /** Desired name of this module. Override this to give this module a custom, perhaps parametric,
+ * name.
+ */
def desiredName = this.getClass.getName.split('.').last
/** Legalized name of this module. */
final val name = Builder.globalNamespace.name(desiredName)
- /** Keep component for signal names */
- private[chisel3] var _component: Option[Component] = None
-
- /** Signal name (for simulation). */
- override def instanceName =
- if (_parent == None) name else _component match {
- case None => getRef.name
- case Some(c) => getRef fullName c
- }
-
- /** IO for this Module. At the Scala level (pre-FIRRTL transformations),
- * connections in and out of a Module may only go through `io` elements.
+ /** Called at the Module.apply(...) level after this Module has finished elaborating.
+ * Returns a map of nodes -> names, for named nodes.
+ *
+ * Helper method.
*/
- def io: Record
- val clock = Port(Input(Clock()))
- val reset = Port(Input(Bool()))
-
- // Setup ClockAndReset
- Builder.currentClockAndReset = Some(ClockAndReset(clock, reset))
-
- private[chisel3] def addId(d: HasId) { _ids += d }
-
- private[core] def ports: Seq[(String,Data)] = Vector(
- ("clock", clock), ("reset", reset), ("io", io)
- )
-
- private[core] def computePorts: Seq[firrtl.Port] = {
- // If we're auto-wrapping IO definitions, do so now.
- if (!(compileOptions.requireIOWrap || ioDefined)) {
- IO(io)
- }
- for ((name, port) <- ports) yield {
- // Port definitions need to know input or output at top-level.
- // By FIRRTL semantics, 'flipped' becomes an Input
- val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output
- firrtl.Port(port, direction)
- }
- }
-
- private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = {
- _parent match {
- case Some(p) => {
- pushCommand(DefInvalid(sourceInfo, io.ref)) // init instance inputs
- clock := override_clock.getOrElse(Builder.forcedClock)
- reset := override_reset.getOrElse(Builder.forcedReset)
- this
+ protected def nameIds(rootClass: Class[_]): HashMap[HasId, String] = {
+ val names = new HashMap[HasId, String]()
+
+ def name(node: HasId, name: String) {
+ // First name takes priority, like suggestName
+ // TODO: DRYify with suggestName
+ if (!names.contains(node)) {
+ names.put(node, name)
}
- case None => this
- }
- }
-
- private[core] def setRefs(): this.type = {
- for ((name, port) <- ports) {
- port.setRef(ModuleIO(this, _namespace.name(name)))
}
/** Recursively suggests names to supported "container" classes
* Arbitrary nestings of supported classes are allowed so long as the
* innermost element is of type HasId
- * Currently supported:
- * - Iterable
- * - Option
- * (Note that Map is Iterable[Tuple2[_,_]] and thus excluded)
+ * (Note: Map is Iterable[Tuple2[_,_]] and thus excluded)
*/
def nameRecursively(prefix: String, nameMe: Any): Unit =
nameMe match {
- case (id: HasId) => id.suggestName(prefix)
+ case (id: HasId) => name(id, prefix)
case Some(elt) => nameRecursively(prefix, elt)
case (iter: Iterable[_]) if iter.hasDefiniteSize =>
for ((elt, i) <- iter.zipWithIndex) {
@@ -221,27 +165,75 @@ extends HasId {
}
case _ => // Do nothing
}
+
/** Scala generates names like chisel3$util$Queue$$ram for private vals
* This extracts the part after $$ for names like this and leaves names
* without $$ unchanged
*/
def cleanName(name: String): String = name.split("""\$\$""").lastOption.getOrElse(name)
- for (m <- getPublicFields(classOf[Module])) {
+
+ for (m <- getPublicFields(rootClass)) {
nameRecursively(cleanName(m.getName), m.invoke(this))
}
- // For Module instances we haven't named, suggest the name of the Module
- _ids foreach {
- case m: Module => m.suggestName(m.desiredName)
- case _ =>
- }
+ names
+ }
+
+ /** Compatibility function. Allows Chisel2 code which had ports without the IO wrapper to
+ * compile under Bindings checks. Does nothing in non-compatibility mode.
+ *
+ * Should NOT be used elsewhere. This API will NOT last.
+ *
+ * TODO: remove this, perhaps by removing Bindings checks in compatibility mode.
+ */
+ def _autoWrapPorts() {}
- // All suggestions are in, force names to every node.
- _ids.foreach(_.forceName(default="_T", _namespace))
- _ids.foreach(_._onModuleClose)
- this
+ //
+ // BaseModule User API functions
+ //
+ protected def annotate(annotation: ChiselAnnotation): Unit = {
+ Builder.annotations += annotation
}
- // For debuggers/testers
- lazy val getPorts = computePorts
- val compileOptions = moduleCompileOptions
+
+ /**
+ * 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 WILL NOT be cloned (to allow for more seamless use of
+ * anonymous Bundles in the IO) and thus CANNOT have been bound to any logic.
+ * This will error if any node is bound (e.g. due to logic in a Bundle
+ * constructor, which is considered improper).
+ *
+ * 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.
+ *
+ * TODO(twigg): Specifically walk the Data definition to call out which nodes
+ * are problematic.
+ */
+ protected def IO[T<:Data](iodef: T): iodef.type = {
+ require(!_closed, "Can't add more ports after module close")
+ // Bind each element of the iodef to being a Port
+ Binding.bind(iodef, PortBinder(this), "Error: iodef")
+ _ports += iodef
+ iodef
+ }
+
+ //
+ // Internal Functions
+ //
+
+ /** Keep component for signal names */
+ private[chisel3] var _component: Option[Component] = None
+
+ /** Signal name (for simulation). */
+ override def instanceName =
+ if (_parent == None) name else _component match {
+ case None => getRef.name
+ case Some(c) => getRef fullName c
+ }
+
}