From db18ae16a26dab5231ca83172c88b9735a977582 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 5 Aug 2022 00:59:23 +0000 Subject: Replace some options with nullable vars (backport #2658) (#2659) * Replace some options with nullable vars (#2658) Co-authored-by: Jack Koenig (cherry picked from commit ac460bfeb16c8e7d0dc00975bb03f73c0fea2103) # Conflicts: # core/src/main/scala/chisel3/internal/Builder.scala * Fix backport conflicts (#2661) Co-authored-by: Zachary Yedidia --- core/src/main/scala/chisel3/internal/Builder.scala | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 61f94f8f..25f4c44c 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,7 +170,7 @@ private[chisel3] trait HasId extends InstanceId { * @return this object */ def suggestName(seed: => String): this.type = { - if (suggested_seed.isEmpty) suggested_seed = Some(seed) + if (suggested_seed.isEmpty) suggested_seedVar = seed naming_prefix = Builder.getPrefix for (hook <- suggest_postseed_hooks.reverse) { hook(seed) } this @@ -171,7 +182,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,11 +223,12 @@ 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)) -- cgit v1.2.3 From 7bad3d2ec316f24f3da79d1dfef19e128cfe8bf5 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 12 Aug 2022 20:04:33 +0000 Subject: Add ability to suppress enum cast warnings (#2671) (#2674) (cherry picked from commit 1ad820f7f549eddcd7188b737f59a240e48a7f0a) Co-authored-by: Zachary Yedidia --- core/src/main/scala/chisel3/internal/Builder.scala | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 25f4c44c..b2c98309 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -435,6 +435,7 @@ private[chisel3] class DynamicContext( var currentReset: Option[Reset] = None val errors = new ErrorLog 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 } @@ -451,6 +452,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 -- cgit v1.2.3 From d344e8a91bdbfedc28527c3fc7d6d243dff9e3e6 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 12 Aug 2022 20:56:42 +0000 Subject: Show equivalent warnings/errors only once (#2673) (#2675) (cherry picked from commit ae76ff4cb303a6646e48dc044be47051b67e7cbb) Co-authored-by: Zachary Yedidia --- core/src/main/scala/chisel3/internal/Error.scala | 41 ++++++++++++++---------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Error.scala b/core/src/main/scala/chisel3/internal/Error.scala index 3b0846eb..98db7109 100644 --- a/core/src/main/scala/chisel3/internal/Error.scala +++ b/core/src/main/scala/chisel3/internal/Error.scala @@ -177,20 +177,31 @@ private[chisel3] object ErrorLog { } private[chisel3] class ErrorLog { + 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) - - /** Log a warning message without a source locator */ - def warningNoLoc(m: => String): Unit = { - errors += new Warning(m, None) + def warning(m: => String): Unit = { + val loc = getUserLineNumber + errors += (((m, getLoc(loc)), new Warning(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, ""), new Warning(m, None))) + /** Emit an informational message */ @deprecated("This method will be removed in 3.5", "3.4") def info(m: String): Unit = @@ -200,11 +211,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 +224,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 +240,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 +296,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 -- cgit v1.2.3 From c4dec947d54a52c3092bd7855180d42afaae3776 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Sat, 13 Aug 2022 00:17:56 +0000 Subject: Add option to treat warnings as errors (backport #2676) (#2677) * Add option to treat warnings as errors (#2676) Add --warnings-as-errors option (cherry picked from commit 498946663726955c380a1e420f5d7b9630000aad) # Conflicts: # core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala # core/src/main/scala/chisel3/internal/Builder.scala # src/main/scala/chisel3/aop/injecting/InjectingAspect.scala # src/main/scala/chisel3/stage/ChiselOptions.scala # src/main/scala/chisel3/stage/package.scala # src/main/scala/chisel3/stage/phases/Elaborate.scala * Resolve backport conflicts Co-authored-by: Zachary Yedidia Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/internal/Builder.scala | 8 +++++--- core/src/main/scala/chisel3/internal/Error.scala | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index b2c98309..75d08f92 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -244,7 +244,8 @@ 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 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." @@ -376,7 +377,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 @@ -433,7 +435,7 @@ 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 diff --git a/core/src/main/scala/chisel3/internal/Error.scala b/core/src/main/scala/chisel3/internal/Error.scala index 98db7109..da968d2a 100644 --- a/core/src/main/scala/chisel3/internal/Error.scala +++ b/core/src/main/scala/chisel3/internal/Error.scala @@ -176,7 +176,7 @@ 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}" @@ -190,17 +190,20 @@ private[chisel3] class ErrorLog { errors += (((m, getLoc(loc)), new Error(m, loc))) } + private def warn(m: => String, loc: Option[StackTraceElement]): LogEntry = + if (warningsAsErrors) new Error(m, loc) else new Warning(m, loc) + /** Log a warning message */ def warning(m: => String): Unit = { val loc = getUserLineNumber - errors += (((m, getLoc(loc)), new Warning(m, loc))) + 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, ""), new Warning(m, None))) + errors += (((m, ""), warn(m, None))) /** Emit an informational message */ @deprecated("This method will be removed in 3.5", "3.4") -- cgit v1.2.3 From 23ef9aa7ffef5bbf8fe124fc9be7683f005c3612 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Tue, 16 Aug 2022 19:04:28 +0000 Subject: Add OpaqueType support to Records (backport #2662) (#2679) * Add OpaqueType support to Records (#2662) OpaqueTypes are essentially type aliases that hide the underlying type. They are implemented in Chisel as Records of a single, unnamed element where the wrapping Record does not exist in the emitted FIRRTL. Co-authored-by: Jack Koenig (cherry picked from commit df5afee2d41b5bcd82d4013b977965c0dfe046fd) * Fix test compilation * Fix OpaqueType tests in RecordSpec Need to implement cloneType correctly and to warn instead of error when accessing .toTarget of non-hardware types because that is a warning (not error) in 3.5. * Waive MiMa false positives Co-authored-by: Aditya Naik <91489422+adkian-sifive@users.noreply.github.com> Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/internal/Builder.scala | 11 ++++++++--- core/src/main/scala/chisel3/internal/firrtl/Converter.scala | 10 ++++++++-- core/src/main/scala/chisel3/internal/firrtl/IR.scala | 6 ++++++ 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 75d08f92..07d8e7f7 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -231,9 +231,13 @@ private[chisel3] trait HasId extends InstanceId { _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), 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 getRef: Arg = _ref.get private[chisel3] def getOptionRef: Option[Arg] = _ref @@ -514,6 +518,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(_, field) => None // Record with single element 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/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index 2d21a7cb..56422b85 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala @@ -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, name) => + convert(imm, ctx, info) case Index(imm, ILit(idx)) => fir.SubIndex(convert(imm, ctx, info), castToInt(idx, "Index"), fir.UnknownType) case Index(imm, value) => @@ -301,7 +303,7 @@ private[chisel3] object Converter { 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: Record => { val childClearDir = clearDir || d.specifiedDirection == SpecifiedDirection.Input || d.specifiedDirection == SpecifiedDirection.Output def eltField(elt: Data): fir.Field = (childClearDir, firrtlUserDirOf(elt)) match { @@ -311,7 +313,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.opaqueType) + fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) }) + else + extractType(d.elements.head._2, true, info) + } } def convert(name: String, param: Param): fir.Param = param match { diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index dc9ab027..37fb2f8b 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), name)) => 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, name: String) extends Arg { + override def contextualName(ctx: Component): String = imm.name + override def localName: 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)}]" -- cgit v1.2.3 From c3b06d773f1fabd2519d6c705d68381d13f1c07f Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Tue, 23 Aug 2022 17:20:12 -0700 Subject: Backport .toTarget deprecation warning information (3.5.x) (#2697) --- core/src/main/scala/chisel3/internal/Builder.scala | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 07d8e7f7..07fc80eb 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -249,10 +249,20 @@ private[chisel3] trait HasId extends InstanceId { // Builder.deprecated mechanism, we have to create our own one off ErrorLog and print the // warning right away. // 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 -- cgit v1.2.3 From 998913f9379440db26b6aeeaa09e7a11d7615351 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 25 Aug 2022 18:14:54 +0000 Subject: Bugfix - OpaqueSlot replace invalid localName (backport #2701) (#2702) * Bugfix - OpaqueSlot replace invalid localName (#2701) (cherry picked from commit fb8ea2a2fac227f2570da992d7877de2eb1cf801) * Fix cloneTypes (#2703) Co-authored-by: Aditya Naik <91489422+adkian-sifive@users.noreply.github.com>--- core/src/main/scala/chisel3/internal/Builder.scala | 4 ++-- core/src/main/scala/chisel3/internal/firrtl/Converter.scala | 2 +- core/src/main/scala/chisel3/internal/firrtl/IR.scala | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 07fc80eb..9f79fe1e 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -233,7 +233,7 @@ private[chisel3] trait HasId extends InstanceId { } private[chisel3] def setRef(parent: HasId, name: String, opaque: Boolean = false): Unit = { if (!opaque) setRef(Slot(Node(parent), name)) - else setRef(OpaqueSlot(Node(parent), name)) + else setRef(OpaqueSlot(Node(parent))) } private[chisel3] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index))) @@ -528,7 +528,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(_, field) => None // Record with single element + 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/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index 56422b85..fe95445c 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala @@ -68,7 +68,7 @@ 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, name) => + case OpaqueSlot(imm) => convert(imm, ctx, info) case Index(imm, ILit(idx)) => fir.SubIndex(convert(imm, ctx, info), castToInt(idx, "Index"), fir.UnknownType) diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index 37fb2f8b..d177c859 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -91,7 +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), name)) => s"${earlyLocalName(imm)}" + case Some(OpaqueSlot(Node(imm))) => s"${earlyLocalName(imm)}" case Some(arg) => arg.name case None => id match { @@ -219,9 +219,9 @@ case class Slot(imm: Node, name: String) extends Arg { } } -case class OpaqueSlot(imm: Node, name: String) extends Arg { +case class OpaqueSlot(imm: Node) extends Arg { override def contextualName(ctx: Component): String = imm.name - override def localName: String = imm.name + override def name: String = imm.name } case class Index(imm: Arg, value: Arg) extends Arg { -- cgit v1.2.3 From 9f1484572e2e4185e87a9cfb03b253870636c12c Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Mon, 29 Aug 2022 21:05:56 +0000 Subject: Fix OpaqueSlot handling of contextual names (#2708) (#2712) We need to ensure that contextual names stay contextual (ie. sensitive to the module context which is important for naming ports). (cherry picked from commit cee255216c4a1bb658a2d8ddc03d966ce7ffb877) Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/internal/firrtl/IR.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index d177c859..ddad6b10 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -220,7 +220,7 @@ case class Slot(imm: Node, name: String) extends Arg { } case class OpaqueSlot(imm: Node) extends Arg { - override def contextualName(ctx: Component): String = imm.name + override def contextualName(ctx: Component): String = imm.contextualName(ctx) override def name: String = imm.name } -- cgit v1.2.3 From 80b3b28f451efa85be50994f732599f043f83d86 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Wed, 19 Oct 2022 14:28:34 -0700 Subject: Don't modify the Builder prefix if reinvoking suggestName on a Data (backport #2789) (#2790) * Only set the chisel3 Builder prefix during the first invocation of suggestName (cherry picked from commit b684506abab2f7b99d56181d548cb8119d317323) # Conflicts: # core/src/main/scala/chisel3/internal/Builder.scala * Add simple test to show bug fix (cherry picked from commit 255068b105de77a045a0016e3a157b52a81c86d6) * Fix merge conflict * Fix test to not use Hardware inside a bundle for prefixing Co-authored-by: Jared Barocsi --- core/src/main/scala/chisel3/internal/Builder.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 9f79fe1e..e3dfff09 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -170,9 +170,12 @@ private[chisel3] trait HasId extends InstanceId { * @return this object */ def suggestName(seed: => String): this.type = { - if (suggested_seed.isEmpty) suggested_seedVar = 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 } -- cgit v1.2.3 From f86c1ff7b39146f23cd1959bcc63dcb3b0b27125 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Sun, 23 Oct 2022 22:27:06 +0000 Subject: Fix for <> to BlackBox.IO with Compatibility Bundles (#2801) (#2803) MonoConnect.traceFlow now properly handles coerced directions. Also minor improvement to getClassName especially useful in test case printf debugging. (cherry picked from commit 3aba755bdcf996c0fbd846d13268fd6641b29e96) Co-authored-by: Megan Wachs --- .../main/scala/chisel3/internal/BiConnect.scala | 9 ++++--- .../main/scala/chisel3/internal/MonoConnect.scala | 30 ++++++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') 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/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) * -- cgit v1.2.3 From 76ada881d077118384907f498576b3b338291ff6 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Mon, 7 Nov 2022 19:13:49 +0000 Subject: Bugfix converter clearing flips (backport #2788) (#2832) * Bugfix converter clearing flips (#2788) * Bugfix: Output on Vec of bundle with mixed field orientations * Bugfix OpaqueTypes clearing flips (cherry picked from commit f05bff1a337589bafebd08783bb0f6a72092a95a) # Conflicts: # src/test/scala/chiselTests/Direction.scala * Resolve backport conflicts Co-authored-by: Adam Izraelevitz Co-authored-by: Jack Koenig Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- core/src/main/scala/chisel3/internal/firrtl/Converter.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index fe95445c..f73e85d2 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala @@ -301,8 +301,11 @@ 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: 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 @@ -316,7 +319,7 @@ private[chisel3] object Converter { if (!d.opaqueType) fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) }) else - extractType(d.elements.head._2, true, info) + extractType(d.elements.head._2, childClearDir, info) } } -- cgit v1.2.3 From bfa9f7465e6069b1e624126f9e14245b69e7c0a9 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Tue, 8 Nov 2022 17:27:07 +0000 Subject: Switch to using experimental trait for OpaqueTypes (backport #2783) (#2836) * Switch to using experimental trait for OpaqueTypes (#2783) This makes it more clear that the feature is experimental. Users may still override the opaqueType method for more dynamic control over when instances of a given Record are OpaqueTypes or not, but they are discouraged from doing so. (cherry picked from commit 7525dc71ccc2050d8e4a68b38f3b76920ba693fc) * Fix cloneType in RecordSpec Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/internal/firrtl/Converter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index f73e85d2..3d6e0d79 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala @@ -316,7 +316,7 @@ private[chisel3] object Converter { case (false, SpecifiedDirection.Flip | SpecifiedDirection.Input) => fir.Field(getRef(elt, info).name, fir.Flip, extractType(elt, false, info)) } - if (!d.opaqueType) + if (!d._isOpaqueType) fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) }) else extractType(d.elements.head._2, childClearDir, info) -- cgit v1.2.3 From c8046636a25474be4c547c6fe9c6d742ea7b1d13 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Fri, 11 Nov 2022 01:40:53 +0000 Subject: Change RawModule._commands to a VectorBuilder (backport #2839) (#2841) * Change RawModule._commands to a VectorBuilder (#2839) * Change RawModule._commands to a VectorBuilder Use the resulting Vector to build the underlying Component's commands and then use those instead of copying the original ArrayBuffer when iterating on commands. Previously, the Component was using a List to hold the commands which is particularly memory inefficient, especially for large modules. * Optimize Converter's handling of Seq[Command] It previously converted the Commands to a List (which, while not captured in the type system, they were already a List) and then used head and tail iteration. This is less efficient with the new underlying Vector implementation. (cherry picked from commit 48a1ef0a3872c6b68d46145764d977926923a270) * Waive false binary compatibility failures Co-authored-by: Jack Koenig Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../scala/chisel3/internal/firrtl/Converter.scala | 116 ++++++++++++--------- 1 file changed, 68 insertions(+), 48 deletions(-) (limited to 'core/src/main/scala/chisel3/internal') diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index 3d6e0d79..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 @@ -215,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 * @@ -226,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 { @@ -347,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, -- cgit v1.2.3