summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/internal
diff options
context:
space:
mode:
authorJack2022-11-11 06:53:04 +0000
committerJack2022-11-11 06:53:04 +0000
commit3ce953c81f06519351c48277e3474b5720ec07ff (patch)
treeac79dcb80d0528c2ae86ca21da4cf424715ab645 /core/src/main/scala/chisel3/internal
parentadccde9998c91875e5490cff6d5822ffacc593ed (diff)
parentc8046636a25474be4c547c6fe9c6d742ea7b1d13 (diff)
Merge branch '3.5.x' into 3.5-release
Diffstat (limited to 'core/src/main/scala/chisel3/internal')
-rw-r--r--core/src/main/scala/chisel3/internal/BiConnect.scala9
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala74
-rw-r--r--core/src/main/scala/chisel3/internal/Error.scala46
-rw-r--r--core/src/main/scala/chisel3/internal/MonoConnect.scala30
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/Converter.scala133
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala6
6 files changed, 198 insertions, 100 deletions
diff --git a/core/src/main/scala/chisel3/internal/BiConnect.scala b/core/src/main/scala/chisel3/internal/BiConnect.scala
index e8fb2361..74376598 100644
--- a/core/src/main/scala/chisel3/internal/BiConnect.scala
+++ b/core/src/main/scala/chisel3/internal/BiConnect.scala
@@ -227,9 +227,12 @@ private[chisel3] object BiConnect {
context_mod: RawModule
): Unit = {
// Verify right has no extra fields that left doesn't have
- for ((field, right_sub) <- right_r.elements) {
- if (!left_r.elements.isDefinedAt(field)) {
- if (connectCompileOptions.connectFieldsMustMatch) {
+
+ // For each field in left, descend with right.
+ // Don't bother doing this check if we don't expect it to necessarily pass.
+ if (connectCompileOptions.connectFieldsMustMatch) {
+ for ((field, right_sub) <- right_r.elements) {
+ if (!left_r.elements.isDefinedAt(field)) {
throw MissingLeftFieldException(field)
}
}
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 61f94f8f..e3dfff09 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -88,10 +88,19 @@ trait InstanceId {
private[chisel3] trait HasId extends InstanceId {
private[chisel3] def _onModuleClose: Unit = {}
- private[chisel3] var _parent: Option[BaseModule] = Builder.currentModule
+ // using nullable var for better memory usage
+ private var _parentVar: BaseModule = Builder.currentModule.getOrElse(null)
+ private[chisel3] def _parent: Option[BaseModule] = Option(_parentVar)
+ private[chisel3] def _parent_=(target: Option[BaseModule]): Unit = {
+ _parentVar = target.getOrElse(null)
+ }
// Set if the returned top-level module of a nested call to the Chisel Builder, see Definition.apply
- private[chisel3] var _circuit: Option[BaseModule] = None
+ private var _circuitVar: BaseModule = null // using nullable var for better memory usage
+ private[chisel3] def _circuit: Option[BaseModule] = Option(_circuitVar)
+ private[chisel3] def _circuit_=(target: Option[BaseModule]): Unit = {
+ _circuitVar = target.getOrElse(null)
+ }
private[chisel3] val _id: Long = Builder.idGen.next
@@ -100,10 +109,12 @@ private[chisel3] trait HasId extends InstanceId {
override def equals(that: Any): Boolean = super.equals(that)
// Contains suggested seed (user-decided seed)
- private var suggested_seed: Option[String] = None
+ private var suggested_seedVar: String = null // using nullable var for better memory usage
+ private def suggested_seed: Option[String] = Option(suggested_seedVar)
// Contains the seed computed automatically by the compiler plugin
- private var auto_seed: Option[String] = None
+ private var auto_seedVar: String = null // using nullable var for better memory usage
+ private def auto_seed: Option[String] = Option(auto_seedVar)
// Prefix for use in naming
// - Defaults to prefix at time when object is created
@@ -131,7 +142,7 @@ private[chisel3] trait HasId extends InstanceId {
private[chisel3] def autoSeed(seed: String): this.type = forceAutoSeed(seed)
// Bypass the overridden behavior of autoSeed in [[Data]], apply autoSeed even to ports
private[chisel3] def forceAutoSeed(seed: String): this.type = {
- auto_seed = Some(seed)
+ auto_seedVar = seed
for (hook <- auto_postseed_hooks.reverse) { hook(seed) }
naming_prefix = Builder.getPrefix
this
@@ -159,9 +170,12 @@ private[chisel3] trait HasId extends InstanceId {
* @return this object
*/
def suggestName(seed: => String): this.type = {
- if (suggested_seed.isEmpty) suggested_seed = Some(seed)
- naming_prefix = Builder.getPrefix
- for (hook <- suggest_postseed_hooks.reverse) { hook(seed) }
+ if (suggested_seed.isEmpty) {
+ suggested_seedVar = seed
+ // Only set the prefix if a seed hasn't been suggested
+ naming_prefix = Builder.getPrefix
+ for (hook <- suggest_postseed_hooks.reverse) { hook(seed) }
+ }
this
}
@@ -171,7 +185,7 @@ private[chisel3] trait HasId extends InstanceId {
private[chisel3] def forceFinalName(seed: String): this.type = {
// This could be called with user prefixes, ignore them
noPrefix {
- suggested_seed = Some(seed)
+ suggested_seedVar = seed
this.suggestName(seed)
}
}
@@ -212,16 +226,21 @@ private[chisel3] trait HasId extends InstanceId {
naming_prefix = Nil
}
- private var _ref: Option[Arg] = None
+ private var _refVar: Arg = null // using nullable var for better memory usage
+ private def _ref: Option[Arg] = Option(_refVar)
private[chisel3] def setRef(imm: Arg): Unit = setRef(imm, false)
private[chisel3] def setRef(imm: Arg, force: Boolean): Unit = {
if (_ref.isEmpty || force) {
- _ref = Some(imm)
+ _refVar = 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))
+ private[chisel3] def setRef(parent: HasId, name: String, opaque: Boolean = false): Unit = {
+ if (!opaque) setRef(Slot(Node(parent), name))
+ else setRef(OpaqueSlot(Node(parent)))
+ }
+
+ 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))
private[chisel3] def getRef: Arg = _ref.get
private[chisel3] def getOptionRef: Option[Arg] = _ref
@@ -232,10 +251,21 @@ private[chisel3] trait HasId extends InstanceId {
// These accesses occur after Chisel elaboration so we cannot use the normal
// Builder.deprecated mechanism, we have to create our own one off ErrorLog and print the
// warning right away.
- val errors = new ErrorLog
+ // It's especially bad because --warnings-as-errors does not work with these warnings
+ val nameGuess = _computeName(None) match {
+ case Some(name) => s": '$name'"
+ case None => ""
+ }
+ val parentGuess = _parent match {
+ case Some(ViewParent) => s", in module '${reifyParent.pathName}'"
+ case Some(p) => s", in module '${p.pathName}'"
+ case None => ""
+ }
+ val errors = new ErrorLog(false)
val logger = new _root_.logger.Logger(this.getClass.getName)
- val msg = "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated. " +
- "This will become an error in Chisel 3.6."
+ val msg =
+ "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated" + nameGuess + parentGuess + ". " +
+ "This will become an error in Chisel 3.6."
errors.deprecated(msg, None)
errors.checkpoint(logger)
_computeName(None).get
@@ -364,7 +394,8 @@ private[chisel3] class ChiselContext() {
private[chisel3] class DynamicContext(
val annotationSeq: AnnotationSeq,
val throwOnFirstError: Boolean,
- val warnReflectiveNaming: Boolean) {
+ val warnReflectiveNaming: Boolean,
+ val warningsAsErrors: Boolean) {
val importDefinitionAnnos = annotationSeq.collect { case a: ImportDefinitionAnnotation[_] => a }
// Map holding the actual names of extModules
@@ -421,8 +452,9 @@ private[chisel3] class DynamicContext(
var whenStack: List[WhenContext] = Nil
var currentClock: Option[Clock] = None
var currentReset: Option[Reset] = None
- val errors = new ErrorLog
+ val errors = new ErrorLog(warningsAsErrors)
val namingStack = new NamingStack
+
// Used to indicate if this is the top-level module of full elaboration, or from a Definition
var inDefinition: Boolean = false
}
@@ -439,6 +471,9 @@ private[chisel3] object Builder extends LazyLogging {
dynamicContextVar.value.get
}
+ // Used to suppress warnings when casting from a UInt to an Enum
+ var suppressEnumCastWarning: Boolean = false
+
// Returns the current dynamic context
def captureContext(): DynamicContext = dynamicContext
// Sets the current dynamic contents
@@ -496,6 +531,7 @@ private[chisel3] object Builder extends LazyLogging {
def buildAggName(id: HasId): Option[String] = {
def getSubName(field: Data): Option[String] = field.getOptionRef.flatMap {
case Slot(_, field) => Some(field) // Record
+ case OpaqueSlot(_) => None // OpaqueSlots don't contribute to the name
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
diff --git a/core/src/main/scala/chisel3/internal/Error.scala b/core/src/main/scala/chisel3/internal/Error.scala
index 3b0846eb..da968d2a 100644
--- a/core/src/main/scala/chisel3/internal/Error.scala
+++ b/core/src/main/scala/chisel3/internal/Error.scala
@@ -176,21 +176,35 @@ private[chisel3] object ErrorLog {
val errTag = s"[${Console.RED}error${Console.RESET}]"
}
-private[chisel3] class ErrorLog {
+private[chisel3] class ErrorLog(warningsAsErrors: Boolean) {
+ def getLoc(loc: Option[StackTraceElement]): String = {
+ loc match {
+ case Some(elt: StackTraceElement) => s"${elt.getFileName}:${elt.getLineNumber}"
+ case None => "(unknown)"
+ }
+ }
/** Log an error message */
- def error(m: => String): Unit =
- errors += new Error(m, getUserLineNumber)
+ def error(m: => String): Unit = {
+ val loc = getUserLineNumber
+ errors += (((m, getLoc(loc)), new Error(m, loc)))
+ }
- /** Log a warning message */
- def warning(m: => String): Unit =
- errors += new Warning(m, getUserLineNumber)
+ private def warn(m: => String, loc: Option[StackTraceElement]): LogEntry =
+ if (warningsAsErrors) new Error(m, loc) else new Warning(m, loc)
- /** Log a warning message without a source locator */
- def warningNoLoc(m: => String): Unit = {
- errors += new Warning(m, None)
+ /** Log a warning message */
+ def warning(m: => String): Unit = {
+ val loc = getUserLineNumber
+ errors += (((m, getLoc(loc)), warn(m, loc)))
}
+ /** Log a warning message without a source locator. This is used when the
+ * locator wouldn't be helpful (e.g., due to lazy values).
+ */
+ def warningNoLoc(m: => String): Unit =
+ errors += (((m, ""), warn(m, None)))
+
/** Emit an informational message */
@deprecated("This method will be removed in 3.5", "3.4")
def info(m: String): Unit =
@@ -200,11 +214,7 @@ private[chisel3] class ErrorLog {
def deprecated(m: => String, location: Option[String]): Unit = {
val sourceLoc = location match {
case Some(loc) => loc
- case None =>
- getUserLineNumber match {
- case Some(elt: StackTraceElement) => s"${elt.getFileName}:${elt.getLineNumber}"
- case None => "(unknown)"
- }
+ case None => getLoc(getUserLineNumber)
}
val thisEntry = (m, sourceLoc)
@@ -217,7 +227,7 @@ private[chisel3] class ErrorLog {
case ((message, sourceLoc), count) =>
logger.warn(s"${ErrorLog.depTag} $sourceLoc ($count calls): $message")
}
- errors.foreach(e => logger.error(e.toString))
+ errors.foreach(e => logger.error(e._2.toString))
if (!deprecations.isEmpty) {
logger.warn(
@@ -233,8 +243,8 @@ private[chisel3] class ErrorLog {
logger.warn(s"""${ErrorLog.warnTag} scalacOptions := Seq("-unchecked", "-deprecation")""")
}
- val allErrors = errors.filter(_.isFatal)
- val allWarnings = errors.filter(!_.isFatal)
+ val allErrors = errors.filter(_._2.isFatal)
+ val allWarnings = errors.filter(!_._2.isFatal)
if (!allWarnings.isEmpty && !allErrors.isEmpty) {
logger.warn(
@@ -289,7 +299,7 @@ private[chisel3] class ErrorLog {
.headOption
}
- private val errors = ArrayBuffer[LogEntry]()
+ private val errors = LinkedHashMap[(String, String), LogEntry]()
private val deprecations = LinkedHashMap[(String, String), Int]()
private val startTime = System.currentTimeMillis
diff --git a/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala
index 31364804..4e762a7c 100644
--- a/core/src/main/scala/chisel3/internal/MonoConnect.scala
+++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala
@@ -322,21 +322,35 @@ private[chisel3] object MonoConnect {
else false
}
- /** Trace flow from child Data to its parent. */
- @tailrec private[chisel3] def traceFlow(currentlyFlipped: Boolean, data: Data, context_mod: RawModule): Boolean = {
- import SpecifiedDirection.{Input => SInput, Flip => SFlip}
+ /** Trace flow from child Data to its parent.
+ *
+ * Returns true if, given the context,
+ * this signal can be a sink when wantsToBeSink = true,
+ * or if it can be a source when wantsToBeSink = false.
+ * Always returns true if the Data does not actually correspond
+ * to a Port.
+ */
+ @tailrec private[chisel3] def traceFlow(
+ wantToBeSink: Boolean,
+ currentlyFlipped: Boolean,
+ data: Data,
+ context_mod: RawModule
+ ): Boolean = {
val sdir = data.specifiedDirection
- val flipped = sdir == SInput || sdir == SFlip
+ val coercedFlip = sdir == SpecifiedDirection.Input
+ val coercedAlign = sdir == SpecifiedDirection.Output
+ val flipped = sdir == SpecifiedDirection.Flip
+ val traceFlipped = ((flipped ^ currentlyFlipped) || coercedFlip) && (!coercedAlign)
data.binding.get match {
- case ChildBinding(parent) => traceFlow(flipped ^ currentlyFlipped, parent, context_mod)
+ case ChildBinding(parent) => traceFlow(wantToBeSink, traceFlipped, parent, context_mod)
case PortBinding(enclosure) =>
val childPort = enclosure != context_mod
- childPort ^ flipped ^ currentlyFlipped
+ wantToBeSink ^ childPort ^ traceFlipped
case _ => true
}
}
- def canBeSink(data: Data, context_mod: RawModule): Boolean = traceFlow(true, data, context_mod)
- def canBeSource(data: Data, context_mod: RawModule): Boolean = traceFlow(false, data, context_mod)
+ def canBeSink(data: Data, context_mod: RawModule): Boolean = traceFlow(true, false, data, context_mod)
+ def canBeSource(data: Data, context_mod: RawModule): Boolean = traceFlow(false, false, data, context_mod)
/** Check whether two aggregates can be bulk connected (<=) in FIRRTL. (MonoConnect case)
*
diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
index 2d21a7cb..ca39608f 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
@@ -8,7 +8,7 @@ import firrtl.{ir => fir}
import chisel3.internal.{castToInt, throwException, HasId}
import scala.annotation.{nowarn, tailrec}
-import scala.collection.immutable.Queue
+import scala.collection.immutable.{Queue, VectorBuilder}
import scala.collection.immutable.LazyList // Needed for 2.12 alias
@nowarn("msg=class Port") // delete when Port becomes private
@@ -68,6 +68,8 @@ private[chisel3] object Converter {
fir.Reference(name, fir.UnknownType)
case Slot(imm, name) =>
fir.SubField(convert(imm, ctx, info), name, fir.UnknownType)
+ case OpaqueSlot(imm) =>
+ convert(imm, ctx, info)
case Index(imm, ILit(idx)) =>
fir.SubIndex(convert(imm, ctx, info), castToInt(idx, "Index"), fir.UnknownType)
case Index(imm, value) =>
@@ -213,7 +215,7 @@ private[chisel3] object Converter {
* @param alt Indicates if currently processing commands in the alternate (else) of the when scope
*/
// TODO we should probably have a different structure in the IR to close elses
- private case class WhenFrame(when: fir.Conditionally, outer: Queue[fir.Statement], alt: Boolean)
+ private case class WhenFrame(when: fir.Conditionally, outer: VectorBuilder[fir.Statement], alt: Boolean)
/** Convert Chisel IR Commands into FIRRTL Statements
*
@@ -224,52 +226,72 @@ private[chisel3] object Converter {
* @return FIRRTL Statement that is equivalent to the input cmds
*/
def convert(cmds: Seq[Command], ctx: Component): fir.Statement = {
- @tailrec
- def rec(acc: Queue[fir.Statement], scope: List[WhenFrame])(cmds: Seq[Command]): Seq[fir.Statement] = {
- if (cmds.isEmpty) {
- assert(scope.isEmpty)
- acc
- } else
- convertSimpleCommand(cmds.head, ctx) match {
- // Most Commands map 1:1
- case Some(stmt) =>
- rec(acc :+ stmt, scope)(cmds.tail)
- // When scoping logic does not map 1:1 and requires pushing/popping WhenFrames
- // Please see WhenFrame for more details
- case None =>
- cmds.head match {
- case WhenBegin(info, pred) =>
- val when = fir.Conditionally(convert(info), convert(pred, ctx, info), fir.EmptyStmt, fir.EmptyStmt)
- val frame = WhenFrame(when, acc, false)
- rec(Queue.empty, frame +: scope)(cmds.tail)
- case WhenEnd(info, depth, _) =>
- val frame = scope.head
- val when =
- if (frame.alt) frame.when.copy(alt = fir.Block(acc))
- else frame.when.copy(conseq = fir.Block(acc))
- // Check if this when has an else
- cmds.tail.headOption match {
- case Some(AltBegin(_)) =>
- assert(!frame.alt, "Internal Error! Unexpected when structure!") // Only 1 else per when
- rec(Queue.empty, frame.copy(when = when, alt = true) +: scope.tail)(cmds.drop(2))
- case _ => // Not followed by otherwise
- // If depth > 0 then we need to close multiple When scopes so we add a new WhenEnd
- // If we're nested we need to add more WhenEnds to ensure each When scope gets
- // properly closed
- val cmdsx = if (depth > 0) WhenEnd(info, depth - 1, false) +: cmds.tail else cmds.tail
- rec(frame.outer :+ when, scope.tail)(cmdsx)
- }
- case OtherwiseEnd(info, depth) =>
- val frame = scope.head
- val when = frame.when.copy(alt = fir.Block(acc))
- // TODO For some reason depth == 1 indicates the last closing otherwise whereas
- // depth == 0 indicates last closing when
- val cmdsx = if (depth > 1) OtherwiseEnd(info, depth - 1) +: cmds.tail else cmds.tail
- rec(scope.head.outer :+ when, scope.tail)(cmdsx)
- }
- }
+ var stmts = new VectorBuilder[fir.Statement]()
+ var scope: List[WhenFrame] = Nil
+ var cmdsIt = cmds.iterator.buffered
+ // Extra var because sometimes we want to push a Command to the head of cmdsIt
+ // This is more efficient than changing the iterator
+ var nextCmd: Command = null
+ while (nextCmd != null || cmdsIt.hasNext) {
+ val cmd = if (nextCmd != null) {
+ val _nextCmd = nextCmd
+ nextCmd = null
+ _nextCmd
+ } else {
+ cmdsIt.next()
+ }
+ convertSimpleCommand(cmd, ctx) match {
+ // Most Commands map 1:1
+ case Some(stmt) =>
+ stmts += stmt
+ // When scoping logic does not map 1:1 and requires pushing/popping WhenFrames
+ // Please see WhenFrame for more details
+ case None =>
+ cmd match {
+ case WhenBegin(info, pred) =>
+ val when = fir.Conditionally(convert(info), convert(pred, ctx, info), fir.EmptyStmt, fir.EmptyStmt)
+ val frame = WhenFrame(when, stmts, false)
+ stmts = new VectorBuilder[fir.Statement]
+ scope = frame :: scope
+ case WhenEnd(info, depth, _) =>
+ val frame = scope.head
+ val when =
+ if (frame.alt) frame.when.copy(alt = fir.Block(stmts.result()))
+ else frame.when.copy(conseq = fir.Block(stmts.result()))
+ // Check if this when has an else
+ cmdsIt.headOption match {
+ case Some(AltBegin(_)) =>
+ assert(!frame.alt, "Internal Error! Unexpected when structure!") // Only 1 else per when
+ scope = frame.copy(when = when, alt = true) :: scope.tail
+ cmdsIt.next() // Consume the AltBegin
+ stmts = new VectorBuilder[fir.Statement]
+ case _ => // Not followed by otherwise
+ // If depth > 0 then we need to close multiple When scopes so we add a new WhenEnd
+ // If we're nested we need to add more WhenEnds to ensure each When scope gets
+ // properly closed
+ if (depth > 0) {
+ nextCmd = WhenEnd(info, depth - 1, false)
+ }
+ stmts = frame.outer
+ stmts += when
+ scope = scope.tail
+ }
+ case OtherwiseEnd(info, depth) =>
+ val frame = scope.head
+ val when = frame.when.copy(alt = fir.Block(stmts.result()))
+ // TODO For some reason depth == 1 indicates the last closing otherwise whereas
+ // depth == 0 indicates last closing when
+ if (depth > 1) {
+ nextCmd = OtherwiseEnd(info, depth - 1)
+ }
+ stmts = frame.outer
+ stmts += when
+ scope = scope.tail
+ }
+ }
}
- fir.Block(rec(Queue.empty, List.empty)(cmds))
+ assert(scope.isEmpty)
+ fir.Block(stmts.result())
}
def convert(width: Width): fir.Width = width match {
@@ -299,9 +321,12 @@ private[chisel3] object Converter {
case d: SInt => fir.SIntType(convert(d.width))
case d: FixedPoint => fir.FixedType(convert(d.width), convert(d.binaryPoint))
case d: Interval => fir.IntervalType(d.range.lowerBound, d.range.upperBound, d.range.firrtlBinaryPoint)
- case d: Analog => fir.AnalogType(convert(d.width))
- case d: Vec[_] => fir.VectorType(extractType(d.sample_element, clearDir, info), d.length)
- case d: Record =>
+ case d: Analog => fir.AnalogType(convert(d.width))
+ case d: Vec[_] =>
+ val childClearDir = clearDir ||
+ d.specifiedDirection == SpecifiedDirection.Input || d.specifiedDirection == SpecifiedDirection.Output
+ fir.VectorType(extractType(d.sample_element, childClearDir, info), d.length)
+ case d: Record => {
val childClearDir = clearDir ||
d.specifiedDirection == SpecifiedDirection.Input || d.specifiedDirection == SpecifiedDirection.Output
def eltField(elt: Data): fir.Field = (childClearDir, firrtlUserDirOf(elt)) match {
@@ -311,7 +336,11 @@ private[chisel3] object Converter {
case (false, SpecifiedDirection.Flip | SpecifiedDirection.Input) =>
fir.Field(getRef(elt, info).name, fir.Flip, extractType(elt, false, info))
}
- fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) })
+ if (!d._isOpaqueType)
+ fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) })
+ else
+ extractType(d.elements.head._2, childClearDir, info)
+ }
}
def convert(name: String, param: Param): fir.Param = param match {
@@ -338,7 +367,7 @@ private[chisel3] object Converter {
def convert(component: Component): fir.DefModule = component match {
case ctx @ DefModule(_, name, ports, cmds) =>
- fir.Module(fir.NoInfo, name, ports.map(p => convert(p)), convert(cmds.toList, ctx))
+ fir.Module(fir.NoInfo, name, ports.map(p => convert(p)), convert(cmds, ctx))
case ctx @ DefBlackBox(id, name, ports, topDir, params) =>
fir.ExtModule(
fir.NoInfo,
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index dc9ab027..ddad6b10 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -91,6 +91,7 @@ object Arg {
case Some(Index(Node(imm), Node(value))) => s"${earlyLocalName(imm)}[${earlyLocalName(imm)}]"
case Some(Index(Node(imm), arg)) => s"${earlyLocalName(imm)}[${arg.localName}]"
case Some(Slot(Node(imm), name)) => s"${earlyLocalName(imm)}.$name"
+ case Some(OpaqueSlot(Node(imm))) => s"${earlyLocalName(imm)}"
case Some(arg) => arg.name
case None =>
id match {
@@ -218,6 +219,11 @@ case class Slot(imm: Node, name: String) extends Arg {
}
}
+case class OpaqueSlot(imm: Node) extends Arg {
+ override def contextualName(ctx: Component): String = imm.contextualName(ctx)
+ override def name: String = imm.name
+}
+
case class Index(imm: Arg, value: Arg) extends Arg {
def name: String = s"[$value]"
override def contextualName(ctx: Component): String = s"${imm.contextualName(ctx)}[${value.contextualName(ctx)}]"