summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
authorAditya Naik2024-06-05 13:09:47 -0700
committerAditya Naik2024-06-05 13:09:47 -0700
commite9d996e2a4f27e194ce3503d3ea8d9651b3ac3c2 (patch)
tree6e3cfbabc9b4542356843b8512946b4a0f8efde3 /core/src/main
parentc60561c8e7c58939e53b5a955f646900139d9c67 (diff)
Readd ports that were deleted for testing
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/scala/chisel3/Data.scala2
-rw-r--r--core/src/main/scala/chisel3/Module.scala104
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala36
-rw-r--r--core/src/main/scala/chisel3/package.scala2
4 files changed, 137 insertions, 7 deletions
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
index 73b8e8c8..1a7a0244 100644
--- a/core/src/main/scala/chisel3/Data.scala
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -211,7 +211,7 @@ package experimental {
* // )
* }}}
*/
- def modulePorts(target: BaseModule): Seq[(String, Data)] = Seq.empty
+ def modulePorts(target: BaseModule): Seq[(String, Data)] = target.getChiselPorts
/** Returns a recursive representation of a module's ports with underscore-qualified names
* {{{
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index 22dbcc6f..3419cda0 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -122,9 +122,9 @@ object Module {
assignCompatDir(vec.sample_element) // This is used in fromChildren computation
}
case SpecifiedDirection.Input | SpecifiedDirection.Output =>
- // forced assign, nothing to do
- // The .bind algorithm will automatically assign the direction here.
- // Thus, no implicit assignment is necessary.
+ // forced assign, nothing to do
+ // The .bind algorithm will automatically assign the direction here.
+ // Thus, no implicit assignment is necessary.
}
}
}
@@ -191,7 +191,47 @@ package experimental {
package internal {
import chisel3.experimental.BaseModule
- object BaseModule {}
+ object BaseModule {
+ private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T) extends PseudoModule {
+ override def toString = s"ModuleClone(${getProto})"
+ // Do not call default addId function, which may modify a module that is already "closed"
+ def getPorts = _portsRecord
+ // ClonePorts that hold the bound ports for this module
+ // Used for setting the refs of both this module and the Record
+ private[BaseModule] var _portsRecord: Record = scala.compiletime.uninitialized
+ // Don't generate a component, but point to the one for the cloned Module
+ private[chisel3] def generateComponent(): Option[Component] = {
+ require(!_closed, "Can't generate module more than once")
+ _closed = true
+ _component = getProto._component
+ None
+ }
+ // Maps proto ports to module clone's ports
+ private[chisel3] lazy val ioMap: Map[Data, Data] = {
+ val name2Port = getPorts.elements
+ getProto.getChiselPorts.map {
+ case (name, data) => data -> name2Port(name)
+ }.toMap
+ }
+
+ private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = {
+ val record = _portsRecord
+ // Use .forceName to re-use default name resolving behavior
+ record.forceName(default = this.desiredName, namespace)
+ // Now take the Ref that forceName set and convert it to the correct Arg
+ val instName = record.getRef match {
+ case Ref(name) => name
+ case bad => throwException(s"Internal Error! Cloned-module Record $record has unexpected ref $bad")
+ }
+ // Set both the record and the module to have the same instance name
+ val ref = ModuleCloneIO(getProto, instName)
+ record.setRef(ref, force = true) // force because we did .forceName first
+ this.setRef(Ref(instName))
+ }
+
+ private[chisel3] override def initializeInParent(): Unit = ()
+ }
+ }
}
package experimental {
@@ -248,6 +288,25 @@ package experimental {
_ids.toSeq
}
+ private val _ports = new ArrayBuffer[Data]()
+
+ // getPorts unfortunately already used for tester compatibility
+ protected[chisel3] 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
+
+ // 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.
* Also closes the module so no more construction can happen inside.
*/
@@ -257,6 +316,26 @@ package experimental {
*/
private[chisel3] def initializeInParent(): Unit
+ private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
+ for (port <- getModulePorts) {
+ port._computeName(None).orElse(names.get(port)) match {
+ case Some(name) =>
+ if (_namespace.contains(name)) {
+ Builder.error(
+ s"""Unable to name port $port to "$name" in $this,""" +
+ " name is already taken by another port!"
+ )
+ }
+ port.setRef(ModuleIO(this, _namespace.name(name)))
+ case None =>
+ Builder.error(
+ s"Unable to name port $port in $this, " +
+ "try making it a public field of the Module"
+ )
+ port.setRef(ModuleIO(this, "<UNNAMED>"))
+ }
+ }
+ }
//
// Chisel Internals
//
@@ -330,6 +409,22 @@ package experimental {
}
}
+ /**
+ * Internal API. Returns a list of this module's generated top-level ports as a map of a String
+ * (FIRRTL name) to the IO object. Only valid after the module is closed.
+ *
+ * Note: for BlackBoxes (but not ExtModules), this returns the contents of the top-level io
+ * object, consistent with what is emitted in FIRRTL.
+ *
+ * TODO: Use SeqMap/VectorMap when those data structures become available.
+ */
+ private[chisel3] def getChiselPorts: Seq[(String, Data)] = {
+ require(_closed, "Can't get ports before module close")
+ _component.get.ports.map { port =>
+ (port.id.getRef.asInstanceOf[ModuleIO].name, port.id)
+ }
+ }
+
/** Called at the Module.apply(...) level after this Module has finished elaborating.
* Returns a map of nodes -> names, for named nodes.
*
@@ -387,6 +482,7 @@ package experimental {
Module.assignCompatDir(iodef)
iodef.bind(PortBinding(this))
+ _ports += iodef
}
/** Private accessor for _bindIoInPlace */
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index 4e724b1b..8eeda03c 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -6,6 +6,7 @@ import scala.util.Try
import scala.annotation.nowarn
import chisel3.experimental.BaseModule
import chisel3.internal._
+import chisel3.internal.BaseModule.ModuleClone
import chisel3.internal.Builder._
import chisel3.internal.firrtl._
import _root_.firrtl.annotations.{IsModule, ModuleTarget}
@@ -34,6 +35,14 @@ abstract class RawModule extends BaseModule {
_component.get.asInstanceOf[DefModule].commands
}
+ //
+ // Other Internal Functions
+ //
+ private var _firrtlPorts: Option[Seq[firrtl.Port]] = None
+
+ @deprecated("Use DataMirror.modulePorts instead. this API will be removed in Chisel 3.6", "Chisel 3.5")
+ lazy val getPorts: Seq[Port] = _firrtlPorts.get
+
// This could be factored into a common utility
private def canBeNamed(id: HasId): Boolean = id match {
case d: Data =>
@@ -56,6 +65,9 @@ abstract class RawModule extends BaseModule {
val names = nameIds(classOf[RawModule])
+ // Ports get first naming priority, since they are part of a Module's IO spec
+ namePorts(names)
+
// Then everything else gets named
val warnReflectiveNaming = Builder.warnReflectiveNaming
for ((node, name) <- names) {
@@ -80,6 +92,7 @@ abstract class RawModule extends BaseModule {
// All suggestions are in, force names to every node.
for (id <- getIds) {
id match {
+ case id: ModuleClone[_] => id.setRefAndPortsRef(_namespace) // special handling
case id: BaseModule => id.forceName(default = id.desiredName, _namespace)
case id: MemBase[_] => id.forceName(default = "MEM", _namespace)
// removed till macros are fixed
@@ -109,7 +122,28 @@ abstract class RawModule extends BaseModule {
closeUnboundIds(names)
- val component = DefModule(this, name, null, Seq.empty)
+ val firrtlPorts = getModulePorts.map { port =>
+ // Special case Vec to make FIRRTL emit the direction of its
+ // element.
+ // Just taking the Vec's specifiedDirection is a bug in cases like
+ // Vec(Flipped()), since the Vec's specifiedDirection is
+ // Unspecified.
+ val direction = port match {
+ case v: Vec[_] =>
+ v.specifiedDirection match {
+ case SpecifiedDirection.Input => SpecifiedDirection.Input
+ case SpecifiedDirection.Output => SpecifiedDirection.Output
+ case SpecifiedDirection.Flip => SpecifiedDirection.flip(v.sample_element.specifiedDirection)
+ case SpecifiedDirection.Unspecified => v.sample_element.specifiedDirection
+ }
+ case _ => port.specifiedDirection
+ }
+
+ Port(port, direction)
+ }
+ _firrtlPorts = Some(firrtlPorts)
+
+ val component = DefModule(this, name, firrtlPorts, _commands.result())
_component = Some(component)
_component
}
diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala
index 856cbbd2..72a3515c 100644
--- a/core/src/main/scala/chisel3/package.scala
+++ b/core/src/main/scala/chisel3/package.scala
@@ -342,7 +342,7 @@ package object chisel3 {
"duplicated with DataMirror.fullModulePorts, this returns an internal API, will be removed in Chisel 3.6",
"Chisel 3.5"
)
- def getModulePorts(m: Module): Seq[Port] = Seq.empty
+ def getModulePorts(m: Module): Seq[Port] = m.getPorts
class BindingException(message: String) extends ChiselException(message)