summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/scala/chisel3')
-rw-r--r--core/src/main/scala/chisel3/Aggregate.scala22
-rw-r--r--core/src/main/scala/chisel3/BlackBox.scala3
-rw-r--r--core/src/main/scala/chisel3/Data.scala6
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala20
4 files changed, 33 insertions, 18 deletions
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala
index 9ccf7dbb..6c11b2db 100644
--- a/core/src/main/scala/chisel3/Aggregate.scala
+++ b/core/src/main/scala/chisel3/Aggregate.scala
@@ -479,9 +479,21 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId with Source
* RTL writers should use [[Bundle]]. See [[Record#elements]] for an example.
*/
abstract class Record(private[chisel3] implicit val compileOptions: CompileOptions) extends Aggregate {
+
+ // Doing this earlier than onModuleClose allows field names to be available for prefixing the names
+ // of hardware created when connecting to one of these elements
+ private def setElementRefs(): Unit = {
+ // Since elements is a map, it is impossible for two elements to have the same
+ // identifier; however, Namespace sanitizes identifiers to make them legal for Firrtl/Verilog
+ // which can cause collisions
+ val _namespace = Namespace.empty
+ for ((name, elt) <- elements) { elt.setRef(this, _namespace.name(name, leadingDigitOk=true)) }
+ }
+
private[chisel3] override def bind(target: Binding, parentDirection: SpecifiedDirection): Unit = {
try {
super.bind(target, parentDirection)
+ setElementRefs()
} catch { // nasty compatibility mode shim, where anything flies
case e: MixedDirectionAggregateException if !compileOptions.dontAssumeDirectionality =>
val resolvedDirection = SpecifiedDirection.fromParent(parentDirection, specifiedDirection)
@@ -633,13 +645,11 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio
case _ => false
}
- // NOTE: This sets up dependent references, it can be done before closing the Module
private[chisel3] override def _onModuleClose: Unit = {
- // Since Bundle names this via reflection, it is impossible for two elements to have the same
- // identifier; however, Namespace sanitizes identifiers to make them legal for Firrtl/Verilog
- // which can cause collisions
- val _namespace = Namespace.empty
- for ((name, elt) <- elements) { elt.setRef(this, _namespace.name(name, leadingDigitOk=true)) }
+ // This is usually done during binding, but these must still be set for unbound Records
+ if (this.binding.isEmpty) {
+ setElementRefs()
+ }
}
private[chisel3] final def allElements: Seq[Element] = elements.toIndexedSeq.flatMap(_._2.allElements)
diff --git a/core/src/main/scala/chisel3/BlackBox.scala b/core/src/main/scala/chisel3/BlackBox.scala
index b204e301..1b093ee1 100644
--- a/core/src/main/scala/chisel3/BlackBox.scala
+++ b/core/src/main/scala/chisel3/BlackBox.scala
@@ -165,7 +165,8 @@ abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param
// Long term solution will be to define BlackBox IO differently as part of
// it not descending from the (current) Module
for ((name, port) <- namedPorts) {
- port.setRef(ModuleIO(this, _namespace.name(name)))
+ // We have to force override the _ref because it was set during IO binding
+ port.setRef(ModuleIO(this, _namespace.name(name)), force = true)
}
// We need to call forceName and onModuleClose on all of the sub-elements
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
index bb45b4d8..5d398aa6 100644
--- a/core/src/main/scala/chisel3/Data.scala
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -9,6 +9,8 @@ import chisel3.internal._
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo}
+import scala.util.Try
+
/** User-specified directions.
*/
sealed abstract class SpecifiedDirection
@@ -374,7 +376,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
// Provides a unhelpful fallback for literals, which should have custom rendering per
// Data-subtype.
// TODO Is this okay for sample_element? It *shouldn't* be visible to users
- protected def bindingToString: String = topBindingOpt match {
+ protected def bindingToString: String = Try(topBindingOpt match {
case None => ""
case Some(OpBinding(enclosure, _)) => s"(OpResult in ${enclosure.desiredName})"
case Some(MemoryPortBinding(enclosure, _)) => s"(MemPort in ${enclosure.desiredName})"
@@ -389,7 +391,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
case Some(DontCareBinding()) => s"(DontCare)"
case Some(ElementLitBinding(litArg)) => s"(unhandled literal)"
case Some(BundleLitBinding(litMap)) => s"(unhandled bundle literal)"
- }
+ }).getOrElse("")
// Return ALL elements at root of this type.
// Contasts with flatten, which returns just Bits
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index ffa99913..3988ac68 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -198,7 +198,10 @@ private[chisel3] trait HasId extends InstanceId {
}
private var _ref: Option[Arg] = None
- private[chisel3] def setRef(imm: Arg): Unit = _ref = Some(imm)
+ private[chisel3] def setRef(imm: Arg, force: Boolean = false): Unit = {
+ assert(force || _ref.isEmpty, s"Internal Error, setRef for $this called twice! first ${_ref.get}, second $imm")
+ _ref = Some(imm)
+ }
private[chisel3] def setRef(parent: HasId, name: String): Unit = setRef(Slot(Node(parent), name))
private[chisel3] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index)))
private[chisel3] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref))
@@ -369,13 +372,12 @@ private[chisel3] object Builder {
*/
def pushPrefix(d: HasId): Boolean = {
def buildAggName(id: HasId): Option[String] = {
- // TODO This is slow, can we store this information upon binding?
- def getSubName(field: Data, parent: Data): Option[String] = parent match {
- case vec: Vec[_] =>
- val idx = vec.indexOf(field)
- if (idx >= 0) Some(idx.toString) else None
- case rec: Record => rec.elements.collectFirst { case (name, d) if d == field => name }
- case _ => Builder.exception(s"Shouldn't see non-Aggregate $parent as parent in ChildBinding!")
+ def getSubName(field: Data): Option[String] = field.getOptionRef.flatMap {
+ case Slot(_, field) => Some(field) // Record
+ case Index(_, ILit(n)) => Some(n.toString) // Vec static indexing
+ case Index(_, ULit(n, _)) => Some(n.toString) // Vec lit indexing
+ case Index(_, _: Node) => None // Vec dynamic indexing
+ case ModuleIO(_, n) => Some(n) // BlackBox port
}
def map2[A, B](a: Option[A], b: Option[A])(f: (A, A) => B): Option[B] =
a.flatMap(ax => b.map(f(ax, _)))
@@ -384,7 +386,7 @@ private[chisel3] object Builder {
case (_: WireBinding | _: RegBinding | _: MemoryPortBinding | _: OpBinding) => data.seedOpt
case ChildBinding(parent) => recData(parent).map { p =>
// And name of the field if we have one, we don't for dynamic indexing of Vecs
- getSubName(data, parent).map(p + "_" + _).getOrElse(p)
+ getSubName(data).map(p + "_" + _).getOrElse(p)
}
case SampleElementBinding(parent) => recData(parent)
case PortBinding(mod) if Builder.currentModule.contains(mod) => data.seedOpt