From 6e9740efd138523dca3de5a871104f91d884c476 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Wed, 22 Sep 2021 02:56:13 +0800 Subject: implement trace API. (#2077) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../main/scala/chisel3/experimental/Trace.scala | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 core/src/main/scala/chisel3/experimental/Trace.scala (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/experimental/Trace.scala b/core/src/main/scala/chisel3/experimental/Trace.scala new file mode 100644 index 00000000..2d965c7b --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/Trace.scala @@ -0,0 +1,69 @@ +package chisel3.experimental + +import chisel3.internal.HasId +import chisel3.{Aggregate, Data, Element, Module} +import firrtl.AnnotationSeq +import firrtl.annotations.{Annotation, CompleteTarget, SingleTargetAnnotation} +import firrtl.transforms.DontTouchAllTargets + +/** The util that records the reference map from original [[Data]]/[[Module]] annotated in Chisel and final FIRRTL. + * @example + * {{{ + * class Dut extends Module { + * val a = WireDefault(Bool()) + * Trace.traceName(a) + * } + * val annos = (new ChiselStage).execute(Seq(ChiselGeneratorAnnotation(() => new Dut))) + * val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[CollideModule] + * // get final reference of `a` Seq(ReferenceTarget("Dut", "Dut", Seq.empty, "a", Seq.empty)) + * val firrtlReferenceOfDutA = finalTarget(annos)(dut.a) + * }}} + * */ +object Trace { + + /** Trace a Instance name. */ + def traceName(x: Module): Unit = { + annotate(new ChiselAnnotation { + def toFirrtl: Annotation = TraceNameAnnotation(x.toAbsoluteTarget, x.toAbsoluteTarget) + }) + } + + /** Trace a Data name. */ + def traceName(x: Data): Unit = { + x match { + case aggregate: Aggregate => + annotate(new ChiselAnnotation { + def toFirrtl: Annotation = TraceNameAnnotation(aggregate.toAbsoluteTarget, aggregate.toAbsoluteTarget) + }) + aggregate.getElements.foreach(traceName) + case element: Element => + annotate(new ChiselAnnotation { + def toFirrtl: Annotation = TraceNameAnnotation(element.toAbsoluteTarget, element.toAbsoluteTarget) + }) + } + } + + /** An Annotation that records the original target annotate from Chisel. + * + * @param target target that should be renamed by [[firrtl.RenameMap]] in the firrtl transforms. + * @param chiselTarget original annotated target in Chisel, which should not be changed or renamed in FIRRTL. + */ + private case class TraceNameAnnotation[T <: CompleteTarget](target: T, chiselTarget: T) + extends SingleTargetAnnotation[T] + with DontTouchAllTargets { + def duplicate(n: T): Annotation = this.copy(target = n) + } + + /** Get [[CompleteTarget]] of the target `x` for `annos`. + * This API can be used to find the final reference to a signal or module which is marked by `traceName` + */ + def finalTarget(annos: AnnotationSeq)(x: HasId): Seq[CompleteTarget] = finalTargetMap(annos) + .getOrElse(x.toAbsoluteTarget, Seq.empty) + + /** Get all traced signal/module for `annos` + * This API can be used to gather all final reference to the signal or module which is marked by `traceName` + */ + def finalTargetMap(annos: AnnotationSeq): Map[CompleteTarget, Seq[CompleteTarget]] = annos.collect { + case TraceNameAnnotation(t, chiselTarget) => chiselTarget -> t + }.groupBy(_._1).map{case (k, v) => k -> v.map(_._2)} +} -- cgit v1.2.3 From d1d38bd096fce8b92468720fbedc835ecda40e6b Mon Sep 17 00:00:00 2001 From: Kevin Laeufer Date: Thu, 23 Sep 2021 11:12:26 -0700 Subject: make all verification statements publically available (#2089) --- core/src/main/scala/chisel3/Assert.scala | 92 -------- core/src/main/scala/chisel3/Printf.scala | 3 +- core/src/main/scala/chisel3/RawModule.scala | 8 +- .../main/scala/chisel3/VerificationStatement.scala | 236 +++++++++++++++++++++ .../main/scala/chisel3/experimental/package.scala | 5 - .../experimental/verification/package.scala | 60 ------ .../scala/chisel3/internal/firrtl/Converter.scala | 4 +- .../main/scala/chisel3/internal/firrtl/IR.scala | 4 +- 8 files changed, 247 insertions(+), 165 deletions(-) delete mode 100644 core/src/main/scala/chisel3/Assert.scala create mode 100644 core/src/main/scala/chisel3/VerificationStatement.scala delete mode 100644 core/src/main/scala/chisel3/experimental/verification/package.scala (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Assert.scala b/core/src/main/scala/chisel3/Assert.scala deleted file mode 100644 index 9a497e1f..00000000 --- a/core/src/main/scala/chisel3/Assert.scala +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3 - -import scala.reflect.macros.blackbox.Context -import scala.language.experimental.macros - -import chisel3.internal._ -import chisel3.internal.Builder.pushCommand -import chisel3.internal.firrtl._ -import chisel3.internal.sourceinfo.SourceInfo - -object assert { - /** Checks for a condition to be valid in the circuit at all times. If the - * condition evaluates to false, the circuit simulation stops with an error. - * - * Does not fire when in reset (defined as the encapsulating Module's - * reset). If your definition of reset is not the encapsulating Module's - * reset, you will need to gate this externally. - * - * May be called outside of a Module (like defined in a function), so - * functions using assert make the standard Module assumptions (single clock - * and single reset). - * - * @param cond condition, assertion fires (simulation fails) when false - * @param message optional format string to print when the assertion fires - * @param data optional bits to print in the message formatting - * - * @note See [[printf.apply(fmt:String* printf]] for format string documentation - * @note currently cannot be used in core Chisel / libraries because macro - * defs need to be compiled first and the SBT project is not set up to do - * that - */ - // Macros currently can't take default arguments, so we need two functions to emulate defaults. - def apply(cond: Bool, message: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = macro apply_impl_msg_data - def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = macro apply_impl - - def apply_impl_msg_data(c: Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { - import c.universe._ - val p = c.enclosingPosition - val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}" - val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do")) - q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message), ..$data)($sourceInfo, $compileOptions)" - } - - def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { - import c.universe._ - val p = c.enclosingPosition - val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}" - val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do")) - q"$apply_impl_do($cond, $condStr, _root_.scala.None)($sourceInfo, $compileOptions)" - } - - def apply_impl_do(cond: Bool, line: String, message: Option[String], data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) { - val escLine = line.replaceAll("%", "%%") - when (!(cond || Module.reset.asBool)) { - val fmt = message match { - case Some(msg) => - s"Assertion failed: $msg\n at $escLine\n" - case None => s"Assertion failed\n at $escLine\n" - } - printf.printfWithoutReset(fmt, data:_*) - pushCommand(Stop(sourceInfo, Builder.forcedClock.ref, 1)) - } - } - - /** An elaboration-time assertion, otherwise the same as the above run-time - * assertion. */ - def apply(cond: Boolean, message: => String) { - Predef.assert(cond, message) - } - - /** A workaround for default-value overloading problems in Scala, just - * 'assert(cond, "")' */ - def apply(cond: Boolean) { - Predef.assert(cond, "") - } -} - -object stop { - /** Terminate execution with a failure code. */ - def apply(code: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = { - when (!Module.reset.asBool) { - pushCommand(Stop(sourceInfo, Builder.forcedClock.ref, code)) - } - } - - /** Terminate execution, indicating success. */ - def apply()(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = { - stop(0) - } -} diff --git a/core/src/main/scala/chisel3/Printf.scala b/core/src/main/scala/chisel3/Printf.scala index cf7821b8..be0146bb 100644 --- a/core/src/main/scala/chisel3/Printf.scala +++ b/core/src/main/scala/chisel3/Printf.scala @@ -6,7 +6,6 @@ import scala.language.experimental.macros import chisel3.internal._ import chisel3.internal.Builder.pushCommand import chisel3.internal.sourceinfo.SourceInfo -import chisel3.experimental.BaseSim /** Prints a message in simulation * @@ -34,7 +33,7 @@ object printf { } /** Named class for [[printf]]s. */ - final class Printf(val pable: Printable) extends BaseSim + final class Printf private[chisel3](val pable: Printable) extends VerificationStatement /** Prints a message in simulation * diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index 27f16ad4..f1b4c1cf 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -5,7 +5,7 @@ package chisel3 import scala.collection.mutable.{ArrayBuffer, HashMap} import scala.util.Try import scala.language.experimental.macros -import chisel3.experimental.{BaseModule, BaseSim} +import chisel3.experimental.BaseModule import chisel3.internal._ import chisel3.internal.BaseModule.{ModuleClone, InstanceClone} import chisel3.internal.Builder._ @@ -81,7 +81,11 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) case id: InstanceClone[_] => id.setAsInstanceRef() case id: BaseModule => id.forceName(None, default=id.desiredName, _namespace) case id: MemBase[_] => id.forceName(None, default="MEM", _namespace) - case id: BaseSim => id.forceName(None, default="SIM", _namespace) + case id: stop.Stop => id.forceName(None, default="stop", _namespace) + case id: assert.Assert => id.forceName(None, default="assert", _namespace) + case id: assume.Assume => id.forceName(None, default="assume", _namespace) + case id: cover.Cover => id.forceName(None, default="cover", _namespace) + case id: printf.Printf => id.forceName(None, default="printf", _namespace) case id: Data => if (id.isSynthesizable) { id.topBinding match { diff --git a/core/src/main/scala/chisel3/VerificationStatement.scala b/core/src/main/scala/chisel3/VerificationStatement.scala new file mode 100644 index 00000000..23adc192 --- /dev/null +++ b/core/src/main/scala/chisel3/VerificationStatement.scala @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import scala.reflect.macros.blackbox.Context +import scala.language.experimental.macros +import chisel3.internal._ +import chisel3.internal.Builder.pushCommand +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.SourceInfo + +import scala.reflect.macros.blackbox + +object assert { + /** Checks for a condition to be valid in the circuit at all times. If the + * condition evaluates to false, the circuit simulation stops with an error. + * + * Does not fire when in reset (defined as the encapsulating Module's + * reset). If your definition of reset is not the encapsulating Module's + * reset, you will need to gate this externally. + * + * May be called outside of a Module (like defined in a function), so + * functions using assert make the standard Module assumptions (single clock + * and single reset). + * + * @param cond condition, assertion fires (simulation fails) when false + * @param message optional format string to print when the assertion fires + * @param data optional bits to print in the message formatting + * + * @note See [[printf.apply(fmt:String* printf]] for format string documentation + * @note currently cannot be used in core Chisel / libraries because macro + * defs need to be compiled first and the SBT project is not set up to do + * that + */ + // Macros currently can't take default arguments, so we need two functions to emulate defaults. + def apply(cond: Bool, message: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assert = macro _applyMacroWithMessage + def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assert = macro _applyMacroWithNoMessage + + /** An elaboration-time assertion. Calls the built-in Scala assert function. */ + def apply(cond: Boolean, message: => String): Unit = Predef.assert(cond, message) + /** An elaboration-time assertion. Calls the built-in Scala assert function. */ + def apply(cond: Boolean): Unit = Predef.assert(cond, "") + + /** Named class for assertions. */ + final class Assert private[chisel3]() extends VerificationStatement + + import VerificationStatement._ + + def _applyMacroWithMessage(c: blackbox.Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { + import c.universe._ + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine")) + q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.Some($message), ..$data)($sourceInfo, $compileOptions)" + } + + def _applyMacroWithNoMessage(c: blackbox.Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { + import c.universe._ + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine")) + q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.None)($sourceInfo, $compileOptions)" + } + + /** Used by our macros. Do not call directly! */ + def _applyWithSourceLine(cond: Bool, line: SourceLineInfo, message: Option[String], data: Bits*) + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assert = { + val id = new Assert() + when(!Module.reset.asBool()) { + Builder.pushCommand(Verification(id, Formal.Assert, sourceInfo, Module.clock.ref, cond.ref, "")) + failureMessage("Assertion", line, cond, message, data) + } + id + } +} + + +object assume { + /** Assumes a condition to be valid in the circuit at all times. + * Acts like an assertion in simulation and imposes a declarative + * assumption on the state explored by formal tools. + * + * Does not fire when in reset (defined as the encapsulating Module's + * reset). If your definition of reset is not the encapsulating Module's + * reset, you will need to gate this externally. + * + * May be called outside of a Module (like defined in a function), so + * functions using assert make the standard Module assumptions (single clock + * and single reset). + * + * @param cond condition, assertion fires (simulation fails) when false + * @param message optional format string to print when the assertion fires + * @param data optional bits to print in the message formatting + * + * @note See [[printf.apply(fmt:String* printf]] for format string documentation + */ + // Macros currently can't take default arguments, so we need two functions to emulate defaults. + def apply(cond: Bool, message: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assume = macro _applyMacroWithMessage + def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assume = macro _applyMacroWithNoMessage + + /** An elaboration-time assumption. Calls the built-in Scala assume function. */ + def apply(cond: Boolean, message: => String): Unit = Predef.assume(cond, message) + /** An elaboration-time assumption. Calls the built-in Scala assume function. */ + def apply(cond: Boolean): Unit = Predef.assume(cond, "") + + /** Named class for assumptions. */ + final class Assume private[chisel3]() extends VerificationStatement + + import VerificationStatement._ + + def _applyMacroWithMessage(c: blackbox.Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { + import c.universe._ + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine")) + q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.Some($message), ..$data)($sourceInfo, $compileOptions)" + } + + def _applyMacroWithNoMessage(c: blackbox.Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { + import c.universe._ + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine")) + q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.None)($sourceInfo, $compileOptions)" + } + + /** Used by our macros. Do not call directly! */ + def _applyWithSourceLine(cond: Bool, line: SourceLineInfo, message: Option[String], data: Bits*) + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assume = { + val id = new Assume() + when(!Module.reset.asBool()) { + Builder.pushCommand(Verification(id, Formal.Assume, sourceInfo, Module.clock.ref, cond.ref, "")) + failureMessage("Assumption", line, cond, message, data) + } + id + } +} + + +object cover { + /** Declares a condition to be covered. + * At ever clock event, a counter is incremented iff the condition is active + * and reset is inactive. + * + * Does not fire when in reset (defined as the encapsulating Module's + * reset). If your definition of reset is not the encapsulating Module's + * reset, you will need to gate this externally. + * + * May be called outside of a Module (like defined in a function), so + * functions using assert make the standard Module assumptions (single clock + * and single reset). + * + * @param cond condition that will be sampled on every clock tick + * @param message a string describing the cover event + */ + // Macros currently can't take default arguments, so we need two functions to emulate defaults. + def apply(cond: Bool, message: String)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Cover = macro _applyMacroWithMessage + def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Cover = macro _applyMacroWithNoMessage + + /** Named class for cover statements. */ + final class Cover private[chisel3]() extends VerificationStatement + + import VerificationStatement._ + + def _applyMacroWithNoMessage(c: blackbox.Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { + import c.universe._ + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine")) + q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.None)($sourceInfo, $compileOptions)" + } + + def _applyMacroWithMessage(c: blackbox.Context)(cond: c.Tree, message: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = { + import c.universe._ + val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine")) + q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.Some($message))($sourceInfo, $compileOptions)" + } + + /** Used by our macros. Do not call directly! */ + def _applyWithSourceLine(cond: Bool, line: SourceLineInfo, message: Option[String]) + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Cover = { + val id = new Cover() + when(!Module.reset.asBool()) { + Builder.pushCommand(Verification(id, Formal.Cover, sourceInfo, Module.clock.ref, cond.ref, "")) + } + id + } +} + +object stop { + /** Terminate execution, indicating success. + * + * @param message a string describing why the simulation was stopped + */ + def apply(message: String = "")(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Stop = { + val stp = new Stop() + when (!Module.reset.asBool) { + pushCommand(Stop(stp, sourceInfo, Builder.forcedClock.ref, 0)) + } + stp + } + + /** Terminate execution with a failure code. */ + @deprecated("Non-zero return codes are not well supported. Please use assert(false.B) if you want to indicate a failure.", "Chisel 3.5") + def apply(code: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Stop = { + val stp = new Stop() + when (!Module.reset.asBool) { + pushCommand(Stop(stp, sourceInfo, Builder.forcedClock.ref, code)) + } + stp + } + + /** Named class for [[stop]]s. */ + final class Stop private[chisel3]()extends VerificationStatement +} + +/** Base class for all verification statements: Assert, Assume, Cover, Stop and Printf. */ +abstract class VerificationStatement extends NamedComponent { + _parent.foreach(_.addId(this)) +} + +/** Helper functions for common functionality required by stop, assert, assume or cover */ +private object VerificationStatement { + + type SourceLineInfo = (String, Int, String) + + def getLine(c: blackbox.Context): SourceLineInfo = { + val p = c.enclosingPosition + (p.source.file.name, p.line, p.lineContent.trim) + } + + // creates a printf to inform the user of a failed assertion or assumption + def failureMessage(kind: String, lineInfo: SourceLineInfo, cond: Bool, message: Option[String], data: Seq[Bits]) + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : Unit = { + val (filename, line, content) = lineInfo + val lineMsg = s"$filename:$line $content".replaceAll("%", "%%") + val fmt = message match { + case Some(msg) => + s"$kind failed: $msg\n at $lineMsg\n" + case None => s"$kind failed\n at $lineMsg\n" + } + when(!cond) { + printf.printfWithoutReset(fmt, data:_*) + } + } +} diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala index 8018159f..0fc79487 100644 --- a/core/src/main/scala/chisel3/experimental/package.scala +++ b/core/src/main/scala/chisel3/experimental/package.scala @@ -166,9 +166,4 @@ package object experimental { val prefix = chisel3.internal.prefix // Use to remove prefixes not in provided scope val noPrefix = chisel3.internal.noPrefix - - /** Base simulation-only component. */ - abstract class BaseSim extends NamedComponent { - _parent.foreach(_.addId(this)) - } } diff --git a/core/src/main/scala/chisel3/experimental/verification/package.scala b/core/src/main/scala/chisel3/experimental/verification/package.scala deleted file mode 100644 index 190083fd..00000000 --- a/core/src/main/scala/chisel3/experimental/verification/package.scala +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental - -import chisel3._ -import chisel3.internal.Builder -import chisel3.internal.firrtl.{Formal, Verification} -import chisel3.internal.sourceinfo.SourceInfo - -package object verification { - - object assert { - /** Named class for assertions. */ - final class Assert(private[chisel3] val predicate: Bool) extends BaseSim - - - def apply(predicate: Bool, msg: String = "")( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions): Assert = { - val a = new Assert(predicate) - when (!Module.reset.asBool) { - val clock = Module.clock - Builder.pushCommand(Verification(a, Formal.Assert, sourceInfo, clock.ref, predicate.ref, msg)) - } - a - } - } - - object assume { - /** Named class for assumes. */ - final class Assume(private[chisel3] val predicate: Bool) extends BaseSim - - def apply(predicate: Bool, msg: String = "")( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions): Assume = { - val a = new Assume(predicate) - when (!Module.reset.asBool) { - val clock = Module.clock - Builder.pushCommand(Verification(a, Formal.Assume, sourceInfo, clock.ref, predicate.ref, msg)) - } - a - } - } - - object cover { - /** Named class for covers. */ - final class Cover(private[chisel3] val predicate: Bool) extends BaseSim - - def apply(predicate: Bool, msg: String = "")( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions): Cover = { - val clock = Module.clock - val c = new Cover(predicate) - when (!Module.reset.asBool) { - Builder.pushCommand(Verification(c, Formal.Cover, sourceInfo, clock.ref, predicate.ref, msg)) - } - c - } - } -} diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index f56c3b15..1dc52823 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala @@ -142,8 +142,8 @@ private[chisel3] object Converter { Some(fir.IsInvalid(convert(info), convert(arg, ctx, info))) case e @ DefInstance(info, id, _) => Some(fir.DefInstance(convert(info), e.name, id.name)) - case Stop(info, clock, ret) => - Some(fir.Stop(convert(info), ret, convert(clock, ctx, info), firrtl.Utils.one)) + case e @ Stop(_, info, clock, ret) => + Some(fir.Stop(convert(info), ret, convert(clock, ctx, info), firrtl.Utils.one, e.name)) case e @ Printf(_, info, clock, pable) => val (fmt, args) = unpack(pable, ctx) Some(fir.Print(convert(info), fir.StringLit(fmt), diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index 0b568548..1a06cd36 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -784,7 +784,7 @@ case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command -case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command +case class Stop(id: stop.Stop, sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Definition case class Port(id: Data, dir: SpecifiedDirection) case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition object Formal extends Enumeration { @@ -792,7 +792,7 @@ object Formal extends Enumeration { val Assume = Value("assume") val Cover = Value("cover") } -case class Verification[T <: BaseSim](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg, +case class Verification[T <: VerificationStatement](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg, predicate: Arg, message: String) extends Definition abstract class Component extends Arg { def id: BaseModule -- cgit v1.2.3 From 790a1806c7c5333cea15abbd2657fa893beb92c9 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Tue, 5 Oct 2021 09:22:14 -0700 Subject: Remove v3.4.0 version of autoNameRecursively (#2149) --- .../main/scala/chisel3/internal/plugin/package.scala | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/internal/plugin/package.scala b/core/src/main/scala/chisel3/internal/plugin/package.scala index c17baf22..9b9b41cd 100644 --- a/core/src/main/scala/chisel3/internal/plugin/package.scala +++ b/core/src/main/scala/chisel3/internal/plugin/package.scala @@ -3,27 +3,8 @@ package chisel3.internal package object plugin { - /** Used by Chisel's compiler plugin to automatically name signals - * DO NOT USE in your normal Chisel code!!! - * - * @param name The name to use - * @param nameMe The thing to be named - * @tparam T The type of the thing to be named - * @return The thing, but now named - * @note This is the version called by chisel3-plugin prior to v3.4.1 - */ - def autoNameRecursively[T <: Any](name: String, nameMe: T): T = { - chisel3.internal.Builder.nameRecursively( - name.replace(" ", ""), - nameMe, - (id: chisel3.internal.HasId, n: String) => id.autoSeed(n) - ) - nameMe - } // The actual implementation - // Cannot be unified with (String, T) => T (v3.4.0 version) because of special behavior of ports - // in .autoSeed private def _autoNameRecursively[T <: Any](prevId: Long, name: String, nameMe: T): T = { chisel3.internal.Builder.nameRecursively( name, -- cgit v1.2.3 From ce15ad50a5c175db06c3bba5e3bf46b6c5466c47 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Tue, 5 Oct 2021 10:27:18 -0700 Subject: Remove all Bundle cloneTypes and chiselRuntimeDeprecate its use (#2052) * Remove all manual cloneTypes and make it chisel runtime deprecated to add one * runtime deprecate cloneType with runtime reflection * [Backport this commit] Bundle: add check that override def cloneType still works (will be made an error later) * Plugin: make it an error to override cloneType and add a test for that * Docs: can't compile the cloneType anymore * BundleSpec: comment out failing test I cannot get to fail or ignore Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/Aggregate.scala | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index 17e46cb3..1892f7c2 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -1146,6 +1146,10 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { */ protected def _cloneTypeImpl: Bundle = { assert(Builder.allowReflectiveAutoCloneType, "reflective autoclonetype is disallowed, this should only happen in testing") + Builder.deprecated( + "The runtime reflection inference for cloneType (_cloneTypeImpl) is deprecated as of Chisel 3.5: " + + "Use the Compiler Plugin to infer cloneType" + ) // This attempts to infer constructor and arguments to clone this Bundle subtype without // requiring the user explicitly overriding cloneType. import scala.language.existentials -- cgit v1.2.3 From 110705eeace4f9165dc6377e55c86a599f37a465 Mon Sep 17 00:00:00 2001 From: Jared Barocsi Date: Tue, 5 Oct 2021 12:33:23 -0700 Subject: Deprecate auto-application of empty argument lists to parameterless functions (#2124) * Migrate nullary funcs to parameterless versions * Make deprecation message and dummy arguments clear and consistent Co-authored-by: Megan Wachs --- core/src/main/scala/chisel3/Aggregate.scala | 2 +- core/src/main/scala/chisel3/Bits.scala | 115 ++++++++++++++++----- core/src/main/scala/chisel3/Clock.scala | 8 +- core/src/main/scala/chisel3/Data.scala | 25 +++-- core/src/main/scala/chisel3/Mem.scala | 2 +- core/src/main/scala/chisel3/Module.scala | 2 +- core/src/main/scala/chisel3/Num.scala | 5 +- core/src/main/scala/chisel3/Reg.scala | 4 +- core/src/main/scala/chisel3/SeqUtils.scala | 2 +- core/src/main/scala/chisel3/StrongEnum.scala | 8 +- core/src/main/scala/chisel3/When.scala | 9 +- core/src/main/scala/chisel3/internal/Builder.scala | 12 +-- core/src/main/scala/chisel3/internal/prefix.scala | 4 +- core/src/main/scala/chisel3/package.scala | 25 ++++- 14 files changed, 161 insertions(+), 62 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index 1892f7c2..4cf427ff 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -54,7 +54,7 @@ sealed abstract class Aggregate extends Data { override def litOption: Option[BigInt] = { // Shift the accumulated value by our width and add in our component, masked by our width. def shiftAdd(accumulator: Option[BigInt], elt: Data): Option[BigInt] = { - (accumulator, elt.litOption()) match { + (accumulator, elt.litOption) match { case (Some(accumulator), Some(eltLit)) => val width = elt.width.get val masked = ((BigInt(1) << width) - 1) & eltLit // also handles the negative case with two's complement diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala index 670f6e7a..b7a4a1a7 100644 --- a/core/src/main/scala/chisel3/Bits.scala +++ b/core/src/main/scala/chisel3/Bits.scala @@ -25,7 +25,10 @@ private[chisel3] sealed trait ToBoolable extends Element { * * @note The width must be known and equal to 1 */ - final def asBool(): Bool = macro SourceInfoWhiteboxTransform.noArg + final def asBool: Bool = macro SourceInfoWhiteboxTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def asBool(dummy: Int*): Bool = macro SourceInfoWhiteboxTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool @@ -222,7 +225,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi * @return this $coll with each bit inverted * @group Bitwise */ - final def unary_~ (): Bits = macro SourceInfoWhiteboxTransform.noArg + final def unary_~ : Bits = macro SourceInfoWhiteboxTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_~(dummy: Int*): Bits = macro SourceInfoWhiteboxTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits @@ -304,10 +310,16 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */ - final def toBools(): Seq[Bool] = macro SourceInfoTransform.noArg + final def toBools: Seq[Bool] = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def toBools(dummy: Int*): Seq[Bool] = macro SourceInfoWhiteboxTransform.noArgDummy /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */ - final def asBools(): Seq[Bool] = macro SourceInfoTransform.noArg + final def asBools: Seq[Bool] = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def asBools(dummy: Int*): Seq[Bool] = macro SourceInfoWhiteboxTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_asBools(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Seq[Bool] = @@ -318,7 +330,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi * @note The arithmetic value is not preserved if the most-significant bit is set. For example, a [[UInt]] of * width 3 and value 7 (0b111) would become an [[SInt]] of width 3 and value -1. */ - final def asSInt(): SInt = macro SourceInfoTransform.noArg + final def asSInt: SInt = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def asSInt(dummy: Int*): SInt = macro SourceInfoWhiteboxTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt @@ -410,7 +425,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U * $constantWidth * @group Arithmetic */ - final def unary_- (): UInt = macro SourceInfoTransform.noArg + final def unary_- : UInt = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_-(dummy: Int*): UInt = macro SourceInfoTransform.noArgDummy /** Unary negation (constant width) * @@ -418,7 +436,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U * $constantWidth * @group Arithmetic */ - final def unary_-% (): UInt = macro SourceInfoTransform.noArg + final def unary_-% : UInt = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_%(dummy: Int*): UInt = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : UInt = 0.U - this @@ -522,7 +543,7 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U */ final def ^ (that: UInt): UInt = macro SourceInfoTransform.thatArg - // override def abs: UInt = macro SourceInfoTransform.noArg + // override def abs: UInt = macro SourceInfoTransform.noArgDummy def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = this /** @group SourceInfoTransformMacro */ @@ -545,21 +566,30 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U * @return a hardware [[Bool]] resulting from every bit of this $coll or'd together * @group Bitwise */ - final def orR(): Bool = macro SourceInfoTransform.noArg + final def orR: Bool = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def orR(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy /** And reduction operator * * @return a hardware [[Bool]] resulting from every bit of this $coll and'd together * @group Bitwise */ - final def andR(): Bool = macro SourceInfoTransform.noArg + final def andR: Bool = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def andR(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy /** Exclusive or (xor) reduction operator * * @return a hardware [[Bool]] resulting from every bit of this $coll xor'd together * @group Bitwise */ - final def xorR(): Bool = macro SourceInfoTransform.noArg + final def xorR: Bool = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def xorR(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_orR(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = redop(sourceInfo, OrReduceOp) @@ -599,7 +629,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U * @return a hardware [[Bool]] asserted if this $coll equals zero * @group Bitwise */ - final def unary_! () : Bool = macro SourceInfoTransform.noArg + final def unary_! : Bool = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_! (dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_unary_! (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : Bool = this === 0.U(1.W) @@ -639,7 +672,11 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U * @return an [[SInt]] equal to this $coll with an additional zero in its most significant bit * @note The width of the returned [[SInt]] is `width of this` + `1`. */ - final def zext(): SInt = macro SourceInfoTransform.noArg + final def zext: SInt = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def zext(dummy: Int*): SInt = macro SourceInfoTransform.noArgDummy + /** @group SourceInfoTransformMacro */ def do_zext(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = pushOp(DefPrim(sourceInfo, SInt(width + 1), ConvertOp, ref)) @@ -716,7 +753,10 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S * $constantWidth * @group Arithmetic */ - final def unary_- (): SInt = macro SourceInfoTransform.noArg + final def unary_- : SInt = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_-(dummy: Int*): SInt = macro SourceInfoTransform.noArgDummy /** Unary negation (constant width) * @@ -724,12 +764,15 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S * $constantWidth * @group Arithmetic */ - final def unary_-% (): SInt = macro SourceInfoTransform.noArg + final def unary_-% : SInt = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_-%(dummy: Int*): SInt = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ - def unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S - this + def do_unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S - this /** @group SourceInfoTransformMacro */ - def unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S -% this + def do_unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S -% this /** add (default - no growth) operator */ override def do_+ (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = @@ -755,7 +798,7 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S final def * (that: UInt): SInt = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_* (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = { - val thatToSInt = that.zext() + val thatToSInt = that.zext val result = binop(sourceInfo, SInt(this.width + thatToSInt.width), TimesOp, thatToSInt) result.tail(1).asSInt } @@ -876,10 +919,10 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S /** @group SourceInfoTransformMacro */ def do_=== (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that) -// final def abs(): UInt = macro SourceInfoTransform.noArg +// final def abs(): UInt = macro SourceInfoTransform.noArgDummy def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = { - Mux(this < 0.S, (-this), this) + Mux(this < 0.S, -this, this) } override def do_<< (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = @@ -938,7 +981,10 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S sealed trait Reset extends Element with ToBoolable { /** Casts this $coll to an [[AsyncReset]] */ - final def asAsyncReset(): AsyncReset = macro SourceInfoWhiteboxTransform.noArg + final def asAsyncReset: AsyncReset = macro SourceInfoWhiteboxTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def asAsyncReset(dummy: Int*): AsyncReset = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset @@ -1124,7 +1170,10 @@ sealed class Bool() extends UInt(1.W) with Reset { def do_&& (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this & that /** Reinterprets this $coll as a clock */ - def asClock(): Clock = macro SourceInfoTransform.noArg + def asClock: Clock = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def asClock(dummy: Int*): Clock = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_asClock(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Clock = pushOp(DefPrim(sourceInfo, Clock(), AsClockOp, ref)) @@ -1220,7 +1269,10 @@ package experimental { * $expandingWidth * @group Arithmetic */ - final def unary_- (): FixedPoint = macro SourceInfoTransform.noArg + final def unary_- : FixedPoint = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_-(dummy: Int*): FixedPoint = macro SourceInfoTransform.noArgDummy /** Unary negation (constant width) * @@ -1228,7 +1280,9 @@ package experimental { * $constantWidth * @group Arithmetic */ - final def unary_-% (): FixedPoint = macro SourceInfoTransform.noArg + final def unary_-% : FixedPoint = macro SourceInfoTransform.noArg + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_-%(dummy: Int*): FixedPoint = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) - this @@ -1663,8 +1717,15 @@ package experimental { } } - final def unary_-(): Interval = macro SourceInfoTransform.noArg - final def unary_-%(): Interval = macro SourceInfoTransform.noArg + final def unary_- : Interval = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_-(dummy: Int*): Interval = macro SourceInfoTransform.noArgDummy + + final def unary_-% : Interval = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def unary_-%(dummy: Int*): Interval = macro SourceInfoTransform.noArgDummy def unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { Interval.Zero - this @@ -1779,7 +1840,7 @@ package experimental { def do_=/= (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that) def do_=== (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that) - // final def abs(): UInt = macro SourceInfoTransform.noArg + // final def abs(): UInt = macro SourceInfoTransform.noArgDummy def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { Mux(this < Interval.Zero, (Interval.Zero - this), this) diff --git a/core/src/main/scala/chisel3/Clock.scala b/core/src/main/scala/chisel3/Clock.scala index edb07908..0400697d 100644 --- a/core/src/main/scala/chisel3/Clock.scala +++ b/core/src/main/scala/chisel3/Clock.scala @@ -32,8 +32,12 @@ sealed class Clock(private[chisel3] val width: Width = Width(1)) extends Element def toPrintable: Printable = PString("CLOCK") /** Returns the contents of the clock wire as a [[Bool]]. */ - final def asBool(): Bool = macro SourceInfoTransform.noArg - def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this.asUInt().asBool() + final def asBool: Bool = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def asBool(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy + + def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this.asUInt.asBool override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)) private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala index 32d83008..4ae29ce8 100644 --- a/core/src/main/scala/chisel3/Data.scala +++ b/core/src/main/scala/chisel3/Data.scala @@ -645,18 +645,28 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { } } - def isLit(): Boolean = litOption.isDefined + def isLit: Boolean = litOption.isDefined + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def isLit(dummy: Int*): Boolean = isLit + /** * If this is a literal that is representable as bits, returns the value as a BigInt. * If not a literal, or not representable as bits (for example, is or contains Analog), returns None. */ - def litOption(): Option[BigInt] + def litOption: Option[BigInt] + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def litOption(dummy: Int*): Option[BigInt] = litOption /** * Returns the literal value if this is a literal that is representable as bits, otherwise crashes. */ - def litValue(): BigInt = litOption.get + def litValue: BigInt = litOption.get + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def litValue(dummy: Int*): BigInt = litValue /** Returns the width, in bits, if currently known. */ final def getWidth: Int = @@ -679,7 +689,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { /** @group SourceInfoTransformMacro */ def do_asTypeOf[T <: Data](that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { val thatCloned = Wire(that.cloneTypeFull) - thatCloned.connectFromBits(this.asUInt()) + thatCloned.connectFromBits(this.asUInt) thatCloned } @@ -695,7 +705,10 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { * @note Aggregates are recursively packed with the first element appearing * in the least-significant bits of the result. */ - final def asUInt(): UInt = macro SourceInfoTransform.noArg + final def asUInt: UInt = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def asUInt(dummy: Int*): UInt = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt @@ -715,7 +728,7 @@ trait WireFactory { val x = t.cloneTypeFull // Bind each element of x to being a Wire - x.bind(WireBinding(Builder.forcedUserModule, Builder.currentWhen())) + x.bind(WireBinding(Builder.forcedUserModule, Builder.currentWhen)) pushCommand(DefWire(sourceInfo, x)) if (!compileOptions.explicitInvalidate) { diff --git a/core/src/main/scala/chisel3/Mem.scala b/core/src/main/scala/chisel3/Mem.scala index 183620b6..aeacf052 100644 --- a/core/src/main/scala/chisel3/Mem.scala +++ b/core/src/main/scala/chisel3/Mem.scala @@ -130,7 +130,7 @@ sealed abstract class MemBase[T <: Data](val t: T, val length: BigInt) extends H t.cloneTypeFull, Node(this), dir, i.ref, Builder.forcedClock.ref) ).id // Bind each element of port to being a MemoryPort - port.bind(MemoryPortBinding(Builder.forcedUserModule, Builder.currentWhen())) + port.bind(MemoryPortBinding(Builder.forcedUserModule, Builder.currentWhen)) port } } diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index 3ae48821..56dce4d5 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -39,7 +39,7 @@ object Module extends SourceInfoDoc { // Save then clear clock and reset to prevent leaking scope, must be set again in the Module val (saveClock, saveReset) = (Builder.currentClock, Builder.currentReset) - val savePrefix = Builder.getPrefix() + val savePrefix = Builder.getPrefix Builder.clearPrefix() Builder.currentClock = None Builder.currentReset = None diff --git a/core/src/main/scala/chisel3/Num.scala b/core/src/main/scala/chisel3/Num.scala index 6dd299f4..219e18f4 100644 --- a/core/src/main/scala/chisel3/Num.scala +++ b/core/src/main/scala/chisel3/Num.scala @@ -148,7 +148,10 @@ trait Num[T <: Data] { * $unchangedWidth * @group Arithmetic */ - final def abs(): T = macro SourceInfoTransform.noArg + final def abs: T = macro SourceInfoTransform.noArg + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + final def abs(dummy: Int*): T = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T diff --git a/core/src/main/scala/chisel3/Reg.scala b/core/src/main/scala/chisel3/Reg.scala index bd9e5311..122c5ebd 100644 --- a/core/src/main/scala/chisel3/Reg.scala +++ b/core/src/main/scala/chisel3/Reg.scala @@ -41,7 +41,7 @@ object Reg { val reg = t.cloneTypeFull val clock = Node(Builder.forcedClock) - reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen())) + reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen)) pushCommand(DefReg(sourceInfo, reg, clock)) reg } @@ -174,7 +174,7 @@ object RegInit { val clock = Builder.forcedClock val reset = Builder.forcedReset - reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen())) + reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen)) requireIsHardware(init, "reg initializer") pushCommand(DefRegInit(sourceInfo, reg, clock.ref, reset.ref, init.ref)) reg diff --git a/core/src/main/scala/chisel3/SeqUtils.scala b/core/src/main/scala/chisel3/SeqUtils.scala index da6fc802..5c86efd3 100644 --- a/core/src/main/scala/chisel3/SeqUtils.scala +++ b/core/src/main/scala/chisel3/SeqUtils.scala @@ -81,7 +81,7 @@ private[chisel3] object SeqUtils { val output = cloneSupertype(in.toSeq map { _._2}, "oneHotMux") def buildAndOrMultiplexor[TT <: Data](inputs: Iterable[(Bool, TT)]): T = { - val masked = for ((s, i) <- inputs) yield Mux(s, i.asUInt(), 0.U) + val masked = for ((s, i) <- inputs) yield Mux(s, i.asUInt, 0.U) masked.reduceLeft(_ | _).asTypeOf(output) } diff --git a/core/src/main/scala/chisel3/StrongEnum.scala b/core/src/main/scala/chisel3/StrongEnum.scala index b3d7cf7d..9ae4c889 100644 --- a/core/src/main/scala/chisel3/StrongEnum.scala +++ b/core/src/main/scala/chisel3/StrongEnum.scala @@ -246,7 +246,7 @@ abstract class EnumFactory { private val enumRecords = mutable.ArrayBuffer.empty[EnumRecord] private def enumNames = enumRecords.map(_.name).toSeq - private def enumValues = enumRecords.map(_.inst.litValue()).toSeq + private def enumValues = enumRecords.map(_.inst.litValue).toSeq private def enumInstances = enumRecords.map(_.inst).toSeq private[chisel3] val enumTypeName = getClass.getName.init @@ -265,7 +265,7 @@ abstract class EnumFactory { def all: Seq[Type] = enumInstances private[chisel3] def nameOfValue(id: BigInt): Option[String] = { - enumRecords.find(_.inst.litValue() == id).map(_.name) + enumRecords.find(_.inst.litValue == id).map(_.name) } protected def Value: Type = macro EnumMacros.ValImpl @@ -291,11 +291,11 @@ abstract class EnumFactory { if (id.litOption.isEmpty) { throwException(s"$enumTypeName defined with a non-literal type") } - if (id.litValue() < this.id) { + if (id.litValue < this.id) { throwException(s"Enums must be strictly increasing: $enumTypeName") } - this.id = id.litValue() + this.id = id.litValue do_Value(name) } diff --git a/core/src/main/scala/chisel3/When.scala b/core/src/main/scala/chisel3/When.scala index a2c20d9a..ca383c0f 100644 --- a/core/src/main/scala/chisel3/When.scala +++ b/core/src/main/scala/chisel3/When.scala @@ -50,7 +50,7 @@ object when { implicit val sourceInfo = UnlocatableSourceInfo val whens = Builder.whenStack whens.foldRight(true.B) { - case (ctx, acc) => acc && ctx.localCond() + case (ctx, acc) => acc && ctx.localCond } } } @@ -81,7 +81,7 @@ final class WhenContext private[chisel3] ( private var scopeOpen = false /** Returns the local condition, inverted for an otherwise */ - private[chisel3] def localCond(): Bool = { + private[chisel3] def localCond: Bool = { implicit val compileOptions = ExplicitCompileOptions.Strict implicit val sourceInfo = UnlocatableSourceInfo val alt = altConds.foldRight(true.B) { @@ -111,7 +111,10 @@ final class WhenContext private[chisel3] ( def otherwise(block: => Any)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = new WhenContext(sourceInfo, None, block, firrtlDepth + 1, cond ++: altConds) - def active(): Boolean = scopeOpen + def active: Boolean = scopeOpen + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def active(dummy: Int*): Boolean = active /* * diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 441abc92..4e68623d 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -105,7 +105,7 @@ private[chisel3] trait HasId extends InstanceId { private var auto_seed: Option[String] = None // Prefix at time when this class is constructed - private val construction_prefix: Prefix = Builder.getPrefix() + private val construction_prefix: Prefix = Builder.getPrefix // Prefix when the latest [[suggestSeed]] or [[autoSeed]] is called private var prefix_seed: Prefix = Nil @@ -133,7 +133,7 @@ private[chisel3] trait HasId extends InstanceId { private[chisel3] def forceAutoSeed(seed: String): this.type = { auto_seed = Some(seed) for(hook <- auto_postseed_hooks) { hook(seed) } - prefix_seed = Builder.getPrefix() + prefix_seed = Builder.getPrefix this } @@ -149,7 +149,7 @@ private[chisel3] trait HasId extends InstanceId { */ def suggestName(seed: =>String): this.type = { if(suggested_seed.isEmpty) suggested_seed = Some(seed) - prefix_seed = Builder.getPrefix() + prefix_seed = Builder.getPrefix for(hook <- suggest_postseed_hooks) { hook(seed) } this } @@ -485,7 +485,7 @@ private[chisel3] object Builder extends LazyLogging { } // Returns the prefix stack at this moment - def getPrefix(): Prefix = chiselContext.get().prefixStack + def getPrefix: Prefix = chiselContext.get().prefixStack def currentModule: Option[BaseModule] = dynamicContextVar.value match { case Some(dyanmicContext) => dynamicContext.currentModule @@ -572,7 +572,7 @@ private[chisel3] object Builder extends LazyLogging { dynamicContext.whenStack = s } - def currentWhen(): Option[WhenContext] = dynamicContext.whenStack.headOption + def currentWhen: Option[WhenContext] = dynamicContext.whenStack.headOption def currentClock: Option[Clock] = dynamicContext.currentClock def currentClock_=(newClock: Option[Clock]): Unit = { @@ -615,7 +615,7 @@ private[chisel3] object Builder extends LazyLogging { } def pushOp[T <: Data](cmd: DefPrim[T]): T = { // Bind each element of the returned Data to being a Op - cmd.id.bind(OpBinding(forcedUserModule, currentWhen())) + cmd.id.bind(OpBinding(forcedUserModule, currentWhen)) pushCommand(cmd).id } diff --git a/core/src/main/scala/chisel3/internal/prefix.scala b/core/src/main/scala/chisel3/internal/prefix.scala index 9dc14901..620d0864 100644 --- a/core/src/main/scala/chisel3/internal/prefix.scala +++ b/core/src/main/scala/chisel3/internal/prefix.scala @@ -51,7 +51,7 @@ private[chisel3] object prefix { // scalastyle:ignore // This causes extra prefixes to be added, and subsequently cleared in the // Module constructor. Thus, we need to just make sure if the previous push // was an incorrect one, to not pop off an empty stack - if(Builder.getPrefix().nonEmpty) Builder.popPrefix() + if(Builder.getPrefix.nonEmpty) Builder.popPrefix() ret } } @@ -77,7 +77,7 @@ private[chisel3] object noPrefix { * @return The return value of the provided function */ def apply[T](f: => T): T = { - val prefix = Builder.getPrefix() + val prefix = Builder.getPrefix Builder.clearPrefix() val ret = f Builder.setPrefix(prefix) diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala index 64cfa8b9..68e482dd 100644 --- a/core/src/main/scala/chisel3/package.scala +++ b/core/src/main/scala/chisel3/package.scala @@ -50,10 +50,18 @@ package object chisel3 { /** Int to UInt conversion, recommended style for variables. */ - def asUInt(): UInt = UInt.Lit(bigint, Width()) + def asUInt: UInt = UInt.Lit(bigint, Width()) + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def asUInt(dummy: Int*): UInt = asUInt + /** Int to SInt conversion, recommended style for variables. */ - def asSInt(): SInt = SInt.Lit(bigint, Width()) + def asSInt: SInt = SInt.Lit(bigint, Width()) + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def asSInt(dummy: Int*): SInt = asSInt + /** Int to UInt conversion with specified width, recommended style for variables. */ def asUInt(width: Width): UInt = UInt.Lit(bigint, width) @@ -68,17 +76,21 @@ package object chisel3 { implicit class fromStringToLiteral(str: String) { /** String to UInt parse, recommended style for constants. */ - def U: UInt = str.asUInt() + def U: UInt = str.asUInt /** String to UInt parse with specified width, recommended style for constants. */ def U(width: Width): UInt = str.asUInt(width) /** String to UInt parse, recommended style for variables. */ - def asUInt(): UInt = { + def asUInt: UInt = { val bigInt = parse(str) UInt.Lit(bigInt, Width(bigInt.bitLength max 1)) } + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def asUInt(dummy: Int*): UInt = asUInt + /** String to UInt parse with specified width, recommended style for variables. */ def asUInt(width: Width): UInt = UInt.Lit(parse(str), width) @@ -107,7 +119,10 @@ package object chisel3 { /** Boolean to Bool conversion, recommended style for variables. */ - def asBool(): Bool = Bool.Lit(boolean) + def asBool: Bool = Bool.Lit(boolean) + + @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") + def asBool(dummy: Int*): Bool = asBool } // Fixed Point is experimental for now, but we alias the implicit conversion classes here -- cgit v1.2.3 From c2985aa6ef95a45d6ce9663a17f835eaba0cb9c5 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Tue, 5 Oct 2021 13:20:28 -0700 Subject: Fix naming of unwrapped val io in Chisel.Modules (#2150) The removal of virtual method io accidentally made the naming of io in compatibility mode Bundles sensitive to the prefix at the time of the first access of the field. It also made .suggestName able to override the name. This commit fixes that issue by forcing the name of the io Data to be "io" no matter what.--- core/src/main/scala/chisel3/RawModule.scala | 2 +- core/src/main/scala/chisel3/internal/Builder.scala | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index f1b4c1cf..c001772b 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -199,7 +199,7 @@ package object internal { tryJavaReflect .orElse(tryScalaReflect) - .map(_.autoSeed("io")) + .map(_.forceFinalName("io")) .orElse { // Fallback if reflection fails, user can wrap in IO(...) self.findPort("io") diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 4e68623d..0a0a3f2d 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -154,6 +154,17 @@ private[chisel3] trait HasId extends InstanceId { this } + // Internal version of .suggestName that can override a user-suggested name + // This only exists for maintaining "val io" naming in compatibility-mode Modules without IO + // wrapping + private[chisel3] def forceFinalName(seed: String): this.type = { + // This could be called with user prefixes, ignore them + noPrefix { + suggested_seed = Some(seed) + this.suggestName(seed) + } + } + /** Computes the name of this HasId, if one exists * @param defaultPrefix Optionally provide a default prefix for computing the name * @param defaultSeed Optionally provide default seed for computing the name -- cgit v1.2.3 From bdba21b032e592b21d117a8d68f166ba3834c205 Mon Sep 17 00:00:00 2001 From: Kamyar Mohajerani Date: Tue, 5 Oct 2021 18:12:57 -0400 Subject: Circular-shift (rotate) operations for UInt (#1140) * change static shift behavior to mod width when width is known * add dynamic shift * basic tests that actually do something * MatchedRotateLeftAndRight based on the idea from @chick * BasicRotate rotate "b001" and compare with known values * Fix check for KnownWidth(0|1) as suggested by @aswaterman * Add dontTouch to UIntOps.io (other tests were also optimized out) Co-authored-by: Chick Markley Co-authored-by: Andrew Waterman --- core/src/main/scala/chisel3/Bits.scala | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala index b7a4a1a7..a96d2732 100644 --- a/core/src/main/scala/chisel3/Bits.scala +++ b/core/src/main/scala/chisel3/Bits.scala @@ -650,6 +650,51 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = binop(sourceInfo, UInt(this.width), DynamicShiftRightOp, that) + /** + * Circular shift to the left + * @param that number of bits to rotate + * @return UInt of same width rotated left n bits + */ + final def rotateLeft(that: Int): UInt = macro SourceInfoWhiteboxTransform.thatArg + + def do_rotateLeft(n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = width match { + case _ if (n == 0) => this + case KnownWidth(w) if (w <= 1) => this + case KnownWidth(w) if n >= w => do_rotateLeft(n % w) + case _ if (n < 0) => do_rotateRight(-n) + case _ => tail(n) ## head(n) + } + + /** + * Circular shift to the right + * @param that number of bits to rotate + * @return UInt of same width rotated right n bits + */ + final def rotateRight(that: Int): UInt = macro SourceInfoWhiteboxTransform.thatArg + + def do_rotateRight(n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = width match { + case _ if (n <= 0) => do_rotateLeft(-n) + case KnownWidth(w) if (w <= 1) => this + case KnownWidth(w) if n >= w => do_rotateRight(n % w) + case _ => this(n - 1, 0) ## (this >> n) + } + + final def rotateRight(that: UInt): UInt = macro SourceInfoWhiteboxTransform.thatArg + + private def dynamicShift(n: UInt, staticShift: (UInt,Int) => UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : UInt = + n.asBools().zipWithIndex.foldLeft(this){ + case (in, (en, sh)) => Mux(en, staticShift(in, 1 << sh), in) + } + + def do_rotateRight(n: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + dynamicShift(n, _ rotateRight _) + + final def rotateLeft(that: UInt): UInt = macro SourceInfoWhiteboxTransform.thatArg + + def do_rotateLeft(n: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + dynamicShift(n, _ rotateLeft _) + + /** Conditionally set or clear a bit * * @param off a dynamic offset -- cgit v1.2.3 From baaa2adcbfcf4fb508d8e5e71345afd1d7e5a352 Mon Sep 17 00:00:00 2001 From: Chick Markley Date: Thu, 7 Oct 2021 14:31:16 -0700 Subject: Fixed bug with unary minus on FixedPoint and Interval (#2154) In `Bits.scala`, `FixedPoint` and `Interval` did not defeine the `do_unary_-` methods (the `do_`) was missing The recent PR #2124 combined with the above fact made DspTools break. This fix is necessary to get that repo to build.--- core/src/main/scala/chisel3/Bits.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala index a96d2732..81b43483 100644 --- a/core/src/main/scala/chisel3/Bits.scala +++ b/core/src/main/scala/chisel3/Bits.scala @@ -1330,9 +1330,9 @@ package experimental { final def unary_-%(dummy: Int*): FixedPoint = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ - def unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) - this + def do_unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) - this /** @group SourceInfoTransformMacro */ - def unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) -% this + def do_unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) -% this /** add (default - no growth) operator */ override def do_+ (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = @@ -1772,10 +1772,11 @@ package experimental { @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") final def unary_-%(dummy: Int*): Interval = macro SourceInfoTransform.noArgDummy - def unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { + /** @group SourceInfoTransformMacro */ + def do_unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { Interval.Zero - this } - def unary_-%(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { + def do_unary_-%(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { Interval.Zero -% this } -- cgit v1.2.3 From d6907893f019ee86573dc81768884150e541dba3 Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Wed, 20 Oct 2021 00:13:34 -0400 Subject: Update computeName and callsites (#2192) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- core/src/main/scala/chisel3/RawModule.scala | 2 +- core/src/main/scala/chisel3/internal/Builder.scala | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index c001772b..d8781ee0 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -44,7 +44,7 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = { for (port <- getModulePorts) { - port.computeName(None, None).orElse(names.get(port)) match { + port._computeName(None, 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,""" + diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 0a0a3f2d..57e7578a 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -170,7 +170,7 @@ private[chisel3] trait HasId extends InstanceId { * @param defaultSeed Optionally provide default seed for computing the name * @return the name, if it can be computed */ - def computeName(defaultPrefix: Option[String], defaultSeed: Option[String]): Option[String] = { + private[chisel3] def _computeName(defaultPrefix: Option[String], defaultSeed: Option[String]): Option[String] = { /** Computes a name of this signal, given the seed and prefix * @param seed * @param prefix @@ -214,7 +214,7 @@ private[chisel3] trait HasId extends InstanceId { // (e.g. tried to suggest a name to part of a Record) private[chisel3] def forceName(prefix: Option[String], default: =>String, namespace: Namespace): Unit = if(_ref.isEmpty) { - val candidate_name = computeName(prefix, Some(default)).get + val candidate_name = _computeName(prefix, Some(default)).get val available_name = namespace.name(candidate_name) setRef(Ref(available_name)) } @@ -234,7 +234,7 @@ private[chisel3] trait HasId extends InstanceId { private def refName(c: Component): String = _ref match { case Some(arg) => arg fullName c - case None => computeName(None, None).get + case None => _computeName(None, None).get } // Helper for reifying views if they map to a single Target -- cgit v1.2.3 From d9722cd96159cd8957cd335d79dbb495260e590d Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Mon, 25 Oct 2021 15:12:53 -0700 Subject: Add Hierarchy trait (#2204) --- .../experimental/hierarchy/Definition.scala | 12 +--- .../chisel3/experimental/hierarchy/Hierarchy.scala | 67 ++++++++++++++++++++++ .../chisel3/experimental/hierarchy/Instance.scala | 15 +---- 3 files changed, 70 insertions(+), 24 deletions(-) create mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala index 0cc3d131..3c4c3c84 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala @@ -18,13 +18,9 @@ import firrtl.annotations.{IsModule, ModuleTarget} * * These definitions are then used to create multiple [[Instance]]s. * - * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object + * @param cloned The internal representation of the definition, which may be either be directly the object, or a clone of an object */ -case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends IsLookupable { - private[chisel3] def proto: A = cloned match { - case Left(value: A) => value - case Right(i: IsClone[A]) => i._proto - } +final case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends IsLookupable with SealedHierarchy[A] { /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! * Instead, mark the field you are accessing with [[@public]] * @@ -43,10 +39,6 @@ case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, I lookup.definitionLookup(that, this) } - /** Updated by calls to [[apply]], to avoid recloning returned Data's */ - private [chisel3] val cache = HashMap[Data, Data]() - - /** @return the context of any Data's return from inside the instance */ private[chisel3] def getInnerDataContext: Option[BaseModule] = proto match { case value: BaseModule => diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala new file mode 100644 index 00000000..8dbc5a54 --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3.experimental.hierarchy + +import chisel3._ +import scala.collection.mutable.{HashMap, HashSet} +import scala.reflect.runtime.universe.WeakTypeTag +import chisel3.internal.BaseModule.IsClone +import chisel3.experimental.BaseModule +import _root_.firrtl.annotations.IsModule +import scala.annotation.implicitNotFound + +/** Super-trait for Instance and Definition + * + * Enables writing functions which are Instance/Definition agnostic + */ +sealed trait Hierarchy[+A] { + private[chisel3] def cloned: Either[A, IsClone[A]] + private[chisel3] def proto: A = cloned match { + case Left(value: A) => value + case Right(i: IsClone[A]) => i._proto + } + + /** Updated by calls to [[_lookup]], to avoid recloning returned Data's */ + private[chisel3] val cache = HashMap[Data, Data]() + private[chisel3] def getInnerDataContext: Option[BaseModule] + + + /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! + * Instead, mark the field you are accessing with [[@public]] + * + * Given a selector function (that) which selects a member from the original, return the + * corresponding member from the hierarhcy. + * + * Our @instantiable and @public macros generate the calls to this apply method + * + * By calling this function, we summon the proper Lookupable typeclass from our implicit scope. + * + * @param that a user-specified lookup function + * @param lookup typeclass which contains the correct lookup function, based on the types of A and B + * @param macroGenerated a value created in the macro, to make it harder for users to use this API + */ + def _lookup[B, C](that: A => B)(implicit lookup: Lookupable[B], macroGenerated: chisel3.internal.MacroGenerated): lookup.C +} + +// Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file. +private[chisel3] trait SealedHierarchy[+A] extends Hierarchy[A] + +object Hierarchy { + implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) { + /** Returns the toTarget of this hierarchy + * @return target of this hierarchy + */ + def toTarget: IsModule = i match { + case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget + case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget + } + + /** Returns the toAbsoluteTarget of this hierarchy + * @return absoluteTarget of this Hierarchy + */ + def toAbsoluteTarget: IsModule = i match { + case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget + case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget + } + } +} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala index 9b17bfce..bda52c1b 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala @@ -16,17 +16,7 @@ import firrtl.annotations.IsModule * * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object */ -case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) { - - /** Returns the original object which is instantiated here. - * If this is an instance of a clone, return that clone's original proto - * - * @return the original object which was instantiated - */ - private[chisel3] def proto: A = cloned match { - case Left(value: A) => value - case Right(i: IsClone[A]) => i._proto - } +final case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends SealedHierarchy[A] { /** @return the context of any Data's return from inside the instance */ private[chisel3] def getInnerDataContext: Option[BaseModule] = cloned match { @@ -43,9 +33,6 @@ case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, Is case Right(i: InstantiableClone[_]) => i._parent } - /** Updated by calls to [[apply]], to avoid recloning returned Data's */ - private [chisel3] val cache = HashMap[Data, Data]() - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! * Instead, mark the field you are accessing with [[@public]] * -- cgit v1.2.3 From 5024b706f0638cf3ebbe634b658fa016941e72ac Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Mon, 25 Oct 2021 16:55:23 -0700 Subject: Bugfix: fix isACloneOf (#2205) --- core/src/main/scala/chisel3/Module.scala | 13 ++++++++++++- .../scala/chisel3/experimental/hierarchy/Lookupable.scala | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index 56dce4d5..1ae65969 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -193,7 +193,18 @@ package internal { // Underlying object of which this is a clone of val _proto: T def getProto: T = _proto - def isACloneOf(a: Any): Boolean = this == a || _proto == a + + /** Determines whether another object is a clone of the same underlying proto + * + * @param a + */ + def hasSameProto(a: Any): Boolean = { + val aProto = a match { + case x: IsClone[BaseModule] => x._proto + case o => o + } + this == aProto || _proto == aProto + } } // Private internal class to serve as a _parent for Data in cloned ports diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala index b9617723..2242c1c4 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala @@ -217,7 +217,7 @@ private[chisel3] object Lookupable { } (m, context) match { case (c, ctx) if ctx == c => Left(c) - case (c, ctx: IsClone[_]) if ctx.isACloneOf(c) => Right(ctx.asInstanceOf[IsClone[A]]) + case (c, ctx: IsClone[_]) if ctx.hasSameProto(c) => Right(ctx.asInstanceOf[IsClone[A]]) case (c, ctx) if c._parent.isEmpty => Left(c) case (_, _) => cloneModuleToContext(Left(m._parent.get), context) match { -- cgit v1.2.3 From 2a68cc0636580db1a5fa98e87727bb3ec870e0bc Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Wed, 27 Oct 2021 15:51:21 -0700 Subject: Add java reflection to hierarchy (#2209) * Add Hierarchy trait * Add Hierarchy trait * Add Hierarchy scaladoc * Add license * Add isA and tests * Add back isA * Make calculate via lazy val * Apply suggestions from code review Co-authored-by: Megan Wachs * Add shouldNot compile * Update src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala Co-authored-by: Jack Koenig * Made protected vals private Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- .../chisel3/experimental/hierarchy/Hierarchy.scala | 31 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala index 8dbc5a54..d1ccfb1b 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala @@ -4,7 +4,7 @@ package chisel3.experimental.hierarchy import chisel3._ import scala.collection.mutable.{HashMap, HashSet} -import scala.reflect.runtime.universe.WeakTypeTag +import scala.reflect.runtime.universe.TypeTag import chisel3.internal.BaseModule.IsClone import chisel3.experimental.BaseModule import _root_.firrtl.annotations.IsModule @@ -25,12 +25,39 @@ sealed trait Hierarchy[+A] { private[chisel3] val cache = HashMap[Data, Data]() private[chisel3] def getInnerDataContext: Option[BaseModule] + /** Determine whether underlying proto is of type provided. + * + * @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class. + * @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure. + * @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type + * + * E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String] + * @return Whether underlying proto is of provided type (with caveats outlined above) + */ + def isA[B : TypeTag]: Boolean = { + val tptag = implicitly[TypeTag[B]] + val name = tptag.tpe.toString + inBaseClasses(name) + } + + private lazy val superClasses = calculateSuperClasses(proto.getClass()) + private def calculateSuperClasses(clz: Class[_]): Set[String] = { + if(clz != null) { + Set(clz.getCanonicalName()) ++ + clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++ + calculateSuperClasses(clz.getSuperclass()) + } else { + Set.empty[String] + } + } + private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz) + /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! * Instead, mark the field you are accessing with [[@public]] * * Given a selector function (that) which selects a member from the original, return the - * corresponding member from the hierarhcy. + * corresponding member from the hierarchy. * * Our @instantiable and @public macros generate the calls to this apply method * -- cgit v1.2.3 From ef8a9c2148f01e058d2986c9d64f0c35f640790c Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Wed, 27 Oct 2021 16:52:56 -0700 Subject: Add Select APIs for Hierarchy package (#2210) * Add Hierarchy trait * Add Hierarchy trait * Add Hierarchy scaladoc * Add license * Add isA and tests * Add back isA * Add new Select APIs for hierarchy package * Update scaladoc * Write outlines for tests * Add tests and fixes to new Select functions * Make calculate via lazy val * Apply suggestions from code review Co-authored-by: Megan Wachs * Apply suggestions from code review Co-authored-by: Megan Wachs * Clean up scaladoc * Add shouldNot compile * Apply suggestions from code review Co-authored-by: Megan Wachs * Bugfix all funcs should analyze root too * Add mdoc, bugfix toDefinition * Make func private, add scaladoc * Update src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala Co-authored-by: Jack Koenig * Made protected vals private * Apply suggestions from code review Co-authored-by: Jack Koenig * Address code review comments * Added additional null check Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/Module.scala | 26 +++++++++++++++++----- .../experimental/hierarchy/Definition.scala | 5 ++++- .../chisel3/experimental/hierarchy/Hierarchy.scala | 20 ++++++++++++++++- .../chisel3/experimental/hierarchy/Instance.scala | 7 +++++- .../experimental/hierarchy/Lookupable.scala | 6 ++--- core/src/main/scala/chisel3/internal/Builder.scala | 2 ++ 6 files changed, 55 insertions(+), 11 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index 1ae65969..263aee61 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -88,6 +88,16 @@ object Module extends SourceInfoDoc { def reset: Reset = Builder.forcedReset /** Returns the current Module */ def currentModule: Option[BaseModule] = Builder.currentModule + + private[chisel3] def do_pseudo_apply[T <: BaseModule](bc: => T) + (implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions): T = { + val parent = Builder.currentModule + + val module: T = bc // bc is actually evaluated here + + module + } } /** Abstract base class for Modules, which behave much like Verilog modules. @@ -357,13 +367,19 @@ package experimental { // // 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().") + this match { + case _: PseudoModule => + case other => + if (!Builder.readyForModuleConstr) { + throwException("Error: attempted to instantiate a Module without wrapping it in Module().") + } } - readyForModuleConstr = false + if (Builder.hasDynamicContext) { + readyForModuleConstr = false - Builder.currentModule = Some(this) - Builder.whenStack = Nil + Builder.currentModule = Some(this) + Builder.whenStack = Nil + } // // Module Construction Internals diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala index 3c4c3c84..8f0c88ad 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala @@ -42,13 +42,16 @@ final case class Definition[+A] private[chisel3] (private[chisel3] cloned: Eithe /** @return the context of any Data's return from inside the instance */ private[chisel3] def getInnerDataContext: Option[BaseModule] = proto match { case value: BaseModule => - val newChild = Module.do_apply(new internal.BaseModule.DefinitionClone(value))(chisel3.internal.sourceinfo.UnlocatableSourceInfo, chisel3.ExplicitCompileOptions.Strict) + val newChild = Module.do_pseudo_apply(new internal.BaseModule.DefinitionClone(value))(chisel3.internal.sourceinfo.UnlocatableSourceInfo, chisel3.ExplicitCompileOptions.Strict) newChild._circuit = value._circuit.orElse(Some(value)) newChild._parent = None Some(newChild) case value: IsInstantiable => None } + override def toDefinition: Definition[A] = this + override def toInstance: Instance[A] = new Instance(cloned) + } /** Factory methods for constructing [[Definition]]s */ diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala index d1ccfb1b..559b0e1a 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala @@ -40,10 +40,22 @@ sealed trait Hierarchy[+A] { inBaseClasses(name) } + + // This code handles a special-case where, within an mdoc context, the type returned from + // scala reflection (typetag) looks different than when returned from java reflection. + // This function detects this case and reshapes the string to match. + private def modifyReplString(clz: String): String = { + if(clz != null) { + clz.split('.').toList match { + case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".") + case other => clz + } + } else clz + } private lazy val superClasses = calculateSuperClasses(proto.getClass()) private def calculateSuperClasses(clz: Class[_]): Set[String] = { if(clz != null) { - Set(clz.getCanonicalName()) ++ + Set(modifyReplString(clz.getCanonicalName())) ++ clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++ calculateSuperClasses(clz.getSuperclass()) } else { @@ -68,6 +80,12 @@ sealed trait Hierarchy[+A] { * @param macroGenerated a value created in the macro, to make it harder for users to use this API */ def _lookup[B, C](that: A => B)(implicit lookup: Lookupable[B], macroGenerated: chisel3.internal.MacroGenerated): lookup.C + + /** @return Return the underlying Definition[A] of this Hierarchy[A] */ + def toDefinition: Definition[A] + + /** @return Convert this Hierarchy[A] as a top-level Instance[A] */ + def toInstance: Instance[A] } // Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file. diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala index bda52c1b..49f882eb 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala @@ -17,6 +17,10 @@ import firrtl.annotations.IsModule * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object */ final case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends SealedHierarchy[A] { + cloned match { + case Left(p: IsClone[_]) => chisel3.internal.throwException("Cannot have a Left with a clone!") + case other => //Ok + } /** @return the context of any Data's return from inside the instance */ private[chisel3] def getInnerDataContext: Option[BaseModule] = cloned match { @@ -52,7 +56,8 @@ final case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either } /** Returns the definition of this Instance */ - def toDefinition: Definition[A] = new Definition(Left(proto)) + override def toDefinition: Definition[A] = new Definition(Left(proto)) + override def toInstance: Instance[A] = this } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala index 2242c1c4..771e2070 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala @@ -211,7 +211,7 @@ private[chisel3] object Lookupable { // Recursive call def rec[A <: BaseModule](m: A): Either[A, IsClone[A]] = { def clone(x: A, p: Option[BaseModule], name: () => String): Either[A, IsClone[A]] = { - val newChild = Module.do_apply(new internal.BaseModule.InstanceClone(x, name)) + val newChild = Module.do_pseudo_apply(new internal.BaseModule.InstanceClone(x, name)) newChild._parent = p Right(newChild) } @@ -233,7 +233,7 @@ private[chisel3] object Lookupable { rec(m) match { case Left(mx) => Right(mx) case Right(i: InstanceClone[_]) => - val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName)) + val newChild = Module.do_pseudo_apply(new InstanceClone(m._proto, () => m.instanceName)) newChild._parent = i._parent Right(newChild) } @@ -241,7 +241,7 @@ private[chisel3] object Lookupable { rec(m) match { case Left(mx) => Right(mx) case Right(i: InstanceClone[_]) => - val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName)) + val newChild = Module.do_pseudo_apply(new InstanceClone(m._proto, () => m.instanceName)) newChild._parent = i._parent Right(newChild) } diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 57e7578a..3761b371 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -561,6 +561,8 @@ private[chisel3] object Builder extends LazyLogging { // A bare api call is, e.g. calling Wire() from the scala console). ) } + def hasDynamicContext: Boolean = dynamicContextVar.value.isDefined + def readyForModuleConstr: Boolean = dynamicContext.readyForModuleConstr def readyForModuleConstr_=(target: Boolean): Unit = { dynamicContext.readyForModuleConstr = target -- cgit v1.2.3 From 0c43dadf60c1485be348115c20690990f0fea940 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Thu, 28 Oct 2021 18:18:34 -0700 Subject: Exposing more APIs from D/I internals (#2220) Exposing more internals of D/I, which are required for supporting D/I with more powerful Chisel libraries: - Exposing IsClone[_] - Exposing InstantiableClone[_] - Gated builders for Instance/Definition - Unsealing Lookupable, with protected accessors for proto and cloned--- core/src/main/scala/chisel3/Module.scala | 46 +++++----- .../experimental/hierarchy/Definition.scala | 10 ++- .../chisel3/experimental/hierarchy/Hierarchy.scala | 8 +- .../chisel3/experimental/hierarchy/Instance.scala | 42 ++++----- .../experimental/hierarchy/IsInstantiable.scala | 2 +- .../experimental/hierarchy/LibraryHooks.scala | 31 +++++++ .../experimental/hierarchy/Lookupable.scala | 100 +++++++++++---------- .../experimental/hierarchy/Underlying.scala | 14 +++ core/src/main/scala/chisel3/internal/Builder.scala | 6 +- 9 files changed, 156 insertions(+), 103 deletions(-) create mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala create mode 100644 core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index 263aee61..7ba24585 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -192,17 +192,16 @@ package experimental { package internal { import chisel3.experimental.BaseModule - import chisel3.experimental.hierarchy.IsInstantiable + import chisel3.experimental.hierarchy.{IsInstantiable, Proto, Clone} object BaseModule { /** Represents a clone of an underlying object. This is used to support CloneModuleAsRecord and Instance/Definition. * * @note We don't actually "clone" anything in the traditional sense but is a placeholder so we lazily clone internal state */ - private [chisel3] trait IsClone[+T] { + trait IsClone[+T] { // Underlying object of which this is a clone of - val _proto: T - def getProto: T = _proto + private[chisel3] def getProto: T /** Determines whether another object is a clone of the same underlying proto * @@ -210,16 +209,16 @@ package internal { */ def hasSameProto(a: Any): Boolean = { val aProto = a match { - case x: IsClone[BaseModule] => x._proto + case x: IsClone[BaseModule] => x.getProto case o => o } - this == aProto || _proto == aProto + this == aProto || getProto == aProto } } // Private internal class to serve as a _parent for Data in cloned ports - private[chisel3] class ModuleClone[T <: BaseModule] (val _proto: T) extends PseudoModule with IsClone[T] { - override def toString = s"ModuleClone(${_proto})" + private[chisel3] class ModuleClone[T <: BaseModule] (val getProto: T) extends PseudoModule with IsClone[T] { + override def toString = s"ModuleClone(${getProto})" def getPorts = _portsRecord // ClonePorts that hold the bound ports for this module // Used for setting the refs of both this module and the Record @@ -232,19 +231,19 @@ package internal { private[chisel3] def generateComponent(): Option[Component] = { require(!_closed, "Can't generate module more than once") _closed = true - _component = _proto._component + _component = getProto._component None } // Maps proto ports to module clone's ports private[chisel3] lazy val ioMap: Map[Data, Data] = { val name2Port = getPorts.elements - _proto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap + getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap } // This module doesn't actually exist in the FIRRTL so no initialization to do private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () // Name of this instance's module is the same as the proto's name - override def desiredName: String = _proto.name + override def desiredName: String = getProto.name private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = { val record = _portsRecord @@ -256,7 +255,7 @@ package internal { 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 - record.setRef(ModuleCloneIO(_proto, instName), force=true) // force because we did .forceName first + record.setRef(ModuleCloneIO(getProto, instName), force=true) // force because we did .forceName first this.setRef(Ref(instName)) } } @@ -270,8 +269,8 @@ package internal { * @note In addition, the instance name of an InstanceClone is going to be the SAME as the proto, but this is not true * for ModuleClone. */ - private[chisel3] final class InstanceClone[T <: BaseModule] (val _proto: T, val instName: () => String) extends PseudoModule with IsClone[T] { - override def toString = s"InstanceClone(${_proto})" + private[chisel3] final class InstanceClone[T <: BaseModule] (val getProto: T, val instName: () => String) extends PseudoModule with IsClone[T] { + override def toString = s"InstanceClone(${getProto})" // No addition components are generated private[chisel3] def generateComponent(): Option[Component] = None // Necessary for toTarget to work @@ -281,7 +280,7 @@ package internal { // Instance name is the same as proto's instance name override def instanceName = instName() // Module name is the same as proto's module name - override def desiredName: String = _proto.name + override def desiredName: String = getProto.name } /** Represents a Definition root module, when accessing something from a definition @@ -292,20 +291,21 @@ package internal { * target whose root is the Definition. This DefinitionClone is used to represent the root parent of the * InstanceClone (which represents the returned module). */ - private[chisel3] class DefinitionClone[T <: BaseModule] (val _proto: T) extends PseudoModule with IsClone[T] { - override def toString = s"DefinitionClone(${_proto})" + private[chisel3] class DefinitionClone[T <: BaseModule] (val getProto: T) extends PseudoModule with IsClone[T] { + override def toString = s"DefinitionClone(${getProto})" // No addition components are generated private[chisel3] def generateComponent(): Option[Component] = None // Necessary for toTarget to work private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () // Module name is the same as proto's module name - override def desiredName: String = _proto.name + override def desiredName: String = getProto.name } /** @note If we are cloning a non-module, we need another object which has the proper _parent set! */ - private[chisel3] final class InstantiableClone[T <: IsInstantiable] (val _proto: T) extends IsClone[T] { - private[chisel3] var _parent: Option[BaseModule] = internal.Builder.currentModule + trait InstantiableClone[T <: IsInstantiable] extends IsClone[T] { + private[chisel3] def _innerContext: experimental.hierarchy.Hierarchy[_] + private[chisel3] def getInnerContext: Option[BaseModule] = _innerContext.getInnerDataContext } /** Record type returned by CloneModuleAsRecord @@ -349,13 +349,13 @@ package internal { package experimental { - import chisel3.experimental.hierarchy.IsInstantiable + import chisel3.experimental.hierarchy.{IsInstantiable, Proto} object BaseModule { implicit class BaseModuleExtensions[T <: BaseModule](b: T) { import chisel3.experimental.hierarchy.{Instance, Definition} - def toInstance: Instance[T] = new Instance(Left(b)) - def toDefinition: Definition[T] = new Definition(Left(b)) + def toInstance: Instance[T] = new Instance(Proto(b)) + def toDefinition: Definition[T] = new Definition(Proto(b)) } } /** Abstract base class for Modules, an instantiable organizational unit for RTL. diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala index 8f0c88ad..2ac61807 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala @@ -18,9 +18,9 @@ import firrtl.annotations.{IsModule, ModuleTarget} * * These definitions are then used to create multiple [[Instance]]s. * - * @param cloned The internal representation of the definition, which may be either be directly the object, or a clone of an object + * @param underlying The internal representation of the definition, which may be either be directly the object, or a clone of an object */ -final case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends IsLookupable with SealedHierarchy[A] { +final case class Definition[+A] private[chisel3] (private[chisel3] underlying: Underlying[A]) extends IsLookupable with SealedHierarchy[A] { /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! * Instead, mark the field you are accessing with [[@public]] * @@ -50,7 +50,8 @@ final case class Definition[+A] private[chisel3] (private[chisel3] cloned: Eithe } override def toDefinition: Definition[A] = this - override def toInstance: Instance[A] = new Instance(cloned) + override def toInstance: Instance[A] = new Instance(underlying) + } @@ -90,6 +91,7 @@ object Definition extends SourceInfoDoc { Builder.annotations ++= ir.annotations module._circuit = Builder.currentModule dynamicContext.globalNamespace.copyTo(Builder.globalNamespace) - new Definition(Left(module)) + new Definition(Proto(module)) } + } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala index 559b0e1a..503e437b 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala @@ -15,10 +15,10 @@ import scala.annotation.implicitNotFound * Enables writing functions which are Instance/Definition agnostic */ sealed trait Hierarchy[+A] { - private[chisel3] def cloned: Either[A, IsClone[A]] - private[chisel3] def proto: A = cloned match { - case Left(value: A) => value - case Right(i: IsClone[A]) => i._proto + private[chisel3] def underlying: Underlying[A] + private[chisel3] def proto: A = underlying match { + case Proto(value: A) => value + case Clone(i: IsClone[A]) => i.getProto } /** Updated by calls to [[_lookup]], to avoid recloning returned Data's */ diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala index 49f882eb..97b62c23 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala @@ -14,27 +14,27 @@ import firrtl.annotations.IsModule * Represents a unique instance of type [[A]] which are marked as @instantiable * Can be created using Instance.apply method. * - * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object + * @param underlying The internal representation of the instance, which may be either be directly the object, or a clone of an object */ -final case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends SealedHierarchy[A] { - cloned match { - case Left(p: IsClone[_]) => chisel3.internal.throwException("Cannot have a Left with a clone!") +final case class Instance[+A] private [chisel3] (private[chisel3] underlying: Underlying[A]) extends SealedHierarchy[A] { + underlying match { + case Proto(p: IsClone[_]) => chisel3.internal.throwException("Cannot have a Proto with a clone!") case other => //Ok } /** @return the context of any Data's return from inside the instance */ - private[chisel3] def getInnerDataContext: Option[BaseModule] = cloned match { - case Left(value: BaseModule) => Some(value) - case Left(value: IsInstantiable) => None - case Right(i: BaseModule) => Some(i) - case Right(i: InstantiableClone[_]) => i._parent + private[chisel3] def getInnerDataContext: Option[BaseModule] = underlying match { + case Proto(value: BaseModule) => Some(value) + case Proto(value: IsInstantiable) => None + case Clone(i: BaseModule) => Some(i) + case Clone(i: InstantiableClone[_]) => i.getInnerContext } /** @return the context this instance. Note that for non-module clones, getInnerDataContext will be the same as getClonedParent */ - private[chisel3] def getClonedParent: Option[BaseModule] = cloned match { - case Left(value: BaseModule) => value._parent - case Right(i: BaseModule) => i._parent - case Right(i: InstantiableClone[_]) => i._parent + private[chisel3] def getClonedParent: Option[BaseModule] = underlying match { + case Proto(value: BaseModule) => value._parent + case Clone(i: BaseModule) => i._parent + case Clone(i: InstantiableClone[_]) => i.getInnerContext } /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! @@ -56,7 +56,7 @@ final case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either } /** Returns the definition of this Instance */ - override def toDefinition: Definition[A] = new Definition(Left(proto)) + override def toDefinition: Definition[A] = new Definition(Proto(proto)) override def toInstance: Instance[A] = this } @@ -67,17 +67,17 @@ object Instance extends SourceInfoDoc { /** If this is an instance of a Module, returns the toTarget of this instance * @return target of this instance */ - def toTarget: IsModule = i.cloned match { - case Left(x: BaseModule) => x.getTarget - case Right(x: IsClone[_] with BaseModule) => x.getTarget + def toTarget: IsModule = i.underlying match { + case Proto(x: BaseModule) => x.getTarget + case Clone(x: IsClone[_] with BaseModule) => x.getTarget } /** If this is an instance of a Module, returns the toAbsoluteTarget of this instance * @return absoluteTarget of this instance */ - def toAbsoluteTarget: IsModule = i.cloned match { - case Left(x) => x.toAbsoluteTarget - case Right(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget + def toAbsoluteTarget: IsModule = i.underlying match { + case Proto(x) => x.toAbsoluteTarget + case Clone(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget } } @@ -97,7 +97,7 @@ object Instance extends SourceInfoDoc { val ports = experimental.CloneModuleAsRecord(definition.proto) val clone = ports._parent.get.asInstanceOf[ModuleClone[T]] clone._madeFromDefinition = true - new Instance(Right(clone)) + new Instance(Clone(clone)) } } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala index 26ba0286..4f3c2d42 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala @@ -12,6 +12,6 @@ trait IsInstantiable object IsInstantiable { implicit class IsInstantiableExtensions[T <: IsInstantiable](i: T) { - def toInstance: Instance[T] = new Instance(Left(i)) + def toInstance: Instance[T] = new Instance(Proto(i)) } } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala new file mode 100644 index 00000000..c16cc633 --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3.experimental.hierarchy + +import scala.annotation.implicitNotFound + +@implicitNotFound("These functions are only for building hierarchy-compatible Chisel libraries! Users beware!") +// DO NOT extend unless you know what you are doing!!!!!! Not for the casual user! +trait InsideHierarchyLibraryExtension + +// Collection of public functions to give non-core-Chisel libraries the ability to build integrations with +// the experimental hierarchy package +object LibraryHooks { + + /** Builds a new instance given a definition and function to create a new instance-specific Underlying, from the + * definition's Underlying + * @note Implicitly requires being inside a Hierarchy Library Extension + */ + def buildInstance[A](definition: Definition[A], + createUnderlying: Underlying[A] => Underlying[A] + )(implicit inside: InsideHierarchyLibraryExtension): Instance[A] = { + new Instance(createUnderlying(definition.underlying)) + } + + /** Builds a new definition given an Underlying implementation + * @note Implicitly requires being inside a Hierarchy Library Extension + */ + def buildDefinition[A](underlying: Underlying[A])(implicit inside: InsideHierarchyLibraryExtension): Definition[A] = { + new Definition(underlying) + } +} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala index 771e2070..ff4d676c 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala @@ -19,7 +19,7 @@ import chisel3.internal.{AggregateViewBinding, Builder, ChildBinding, ViewBindin */ @implicitNotFound("@public is only legal within a class marked @instantiable and only on vals of type" + " Data, BaseModule, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable or Option") -sealed trait Lookupable[-B] { +trait Lookupable[-B] { type C // Return type of the lookup /** Function called to modify the returned value of type B from A, into C * @@ -36,9 +36,11 @@ sealed trait Lookupable[-B] { * @return */ def definitionLookup[A](that: A => B, definition: Definition[A]): C + protected def getProto[A](h: Hierarchy[A]): A = h.proto + protected def getUnderlying[A](h: Hierarchy[A]): Underlying[A] = h.underlying } -private[chisel3] object Lookupable { +object Lookupable { /** Clones a data and sets its internal references to its parent module to be in a new context. * @@ -52,10 +54,10 @@ private[chisel3] object Lookupable { data._parent match { case None => data case Some(parent) => - val newParent = cloneModuleToContext(Left(parent), context) + val newParent = cloneModuleToContext(Proto(parent), context) newParent match { - case Left(p) if p == parent => data - case Right(m: BaseModule) => + case Proto(p) if p == parent => data + case Clone(m: BaseModule) => val newChild = data.cloneTypeFull newChild.setRef(data.getRef, true) newChild.bind(internal.CrossModuleBinding) @@ -145,7 +147,7 @@ private[chisel3] object Lookupable { val result = data.cloneTypeFull - // We have to lookup the target(s) of the view since they may need to be cloned into the current context + // We have to lookup the target(s) of the view since they may need to be underlying into the current context val newBinding = data.topBinding match { case ViewBinding(target) => ViewBinding(lookupData(reify(target))) case avb @ AggregateViewBinding(map, targetOpt) => data match { @@ -199,51 +201,51 @@ private[chisel3] object Lookupable { * This function effectively recurses up the parents of module to find whether: * (1) A parent is already in the context; then we do nothing and return module * (2) A parent is in a different clone of the context; then we clone all the parents up - * to that parent and set their parents to be in this cloned context + * to that parent and set their parents to be in this underlying context * (3) A parent has no root; in that case, we do nothing and return the module. * - * @param module original or clone to be cloned into a new context + * @param module original or clone to be underlying into a new context * @param context new context * @return original or clone in the new context */ - private[chisel3] def cloneModuleToContext[T <: BaseModule](module: Either[T, IsClone[T]], context: BaseModule) - (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Either[T, IsClone[T]] = { + private[chisel3] def cloneModuleToContext[T <: BaseModule](module: Underlying[T], context: BaseModule) + (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Underlying[T] = { // Recursive call - def rec[A <: BaseModule](m: A): Either[A, IsClone[A]] = { - def clone(x: A, p: Option[BaseModule], name: () => String): Either[A, IsClone[A]] = { + def rec[A <: BaseModule](m: A): Underlying[A] = { + def clone(x: A, p: Option[BaseModule], name: () => String): Underlying[A] = { val newChild = Module.do_pseudo_apply(new internal.BaseModule.InstanceClone(x, name)) newChild._parent = p - Right(newChild) + Clone(newChild) } (m, context) match { - case (c, ctx) if ctx == c => Left(c) - case (c, ctx: IsClone[_]) if ctx.hasSameProto(c) => Right(ctx.asInstanceOf[IsClone[A]]) - case (c, ctx) if c._parent.isEmpty => Left(c) + case (c, ctx) if ctx == c => Proto(c) + case (c, ctx: IsClone[_]) if ctx.hasSameProto(c) => Clone(ctx.asInstanceOf[IsClone[A]]) + case (c, ctx) if c._parent.isEmpty => Proto(c) case (_, _) => - cloneModuleToContext(Left(m._parent.get), context) match { - case Left(p) => Left(m) - case Right(p: BaseModule) => + cloneModuleToContext(Proto(m._parent.get), context) match { + case Proto(p) => Proto(m) + case Clone(p: BaseModule) => clone(m, Some(p), () => m.instanceName) } } } module match { - case Left(m) => rec(m) - case Right(m: ModuleClone[_]) => + case Proto(m) => rec(m) + case Clone(m: ModuleClone[_]) => rec(m) match { - case Left(mx) => Right(mx) - case Right(i: InstanceClone[_]) => - val newChild = Module.do_pseudo_apply(new InstanceClone(m._proto, () => m.instanceName)) + case Proto(mx) => Clone(mx) + case Clone(i: InstanceClone[_]) => + val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName)) newChild._parent = i._parent - Right(newChild) + Clone(newChild) } - case Right(m: InstanceClone[_]) => + case Clone(m: InstanceClone[_]) => rec(m) match { - case Left(mx) => Right(mx) - case Right(i: InstanceClone[_]) => - val newChild = Module.do_pseudo_apply(new InstanceClone(m._proto, () => m.instanceName)) + case Proto(mx) => Clone(mx) + case Clone(i: InstanceClone[_]) => + val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName)) newChild._parent = i._parent - Right(newChild) + Clone(newChild) } } } @@ -259,14 +261,14 @@ private[chisel3] object Lookupable { type C = Instance[B] def definitionLookup[A](that: A => Instance[B], definition: Definition[A]): C = { val ret = that(definition.proto) - new Instance(cloneModuleToContext(ret.cloned, definition.getInnerDataContext.get)) + new Instance(cloneModuleToContext(ret.underlying, definition.getInnerDataContext.get)) } def instanceLookup[A](that: A => Instance[B], instance: Instance[A]): C = { val ret = that(instance.proto) - instance.cloned match { + instance.underlying match { // If instance is just a normal module, no changing of context is necessary - case Left(_) => new Instance(ret.cloned) - case Right(_) => new Instance(cloneModuleToContext(ret.cloned, instance.getInnerDataContext.get)) + case Proto(_) => new Instance(ret.underlying) + case Clone(_) => new Instance(cloneModuleToContext(ret.underlying, instance.getInnerDataContext.get)) } } } @@ -275,14 +277,14 @@ private[chisel3] object Lookupable { type C = Instance[B] def definitionLookup[A](that: A => B, definition: Definition[A]): C = { val ret = that(definition.proto) - new Instance(cloneModuleToContext(Left(ret), definition.getInnerDataContext.get)) + new Instance(cloneModuleToContext(Proto(ret), definition.getInnerDataContext.get)) } def instanceLookup[A](that: A => B, instance: Instance[A]): C = { val ret = that(instance.proto) - instance.cloned match { + instance.underlying match { // If instance is just a normal module, no changing of context is necessary - case Left(_) => new Instance(Left(ret)) - case Right(_) => new Instance(cloneModuleToContext(Left(ret), instance.getInnerDataContext.get)) + case Proto(_) => new Instance(Proto(ret)) + case Clone(_) => new Instance(cloneModuleToContext(Proto(ret), instance.getInnerDataContext.get)) } } } @@ -299,9 +301,9 @@ private[chisel3] object Lookupable { } def instanceLookup[A](that: A => B, instance: Instance[A]): C = { val ret = that(instance.proto) - val ioMap: Option[Map[Data, Data]] = instance.cloned match { - case Right(x: ModuleClone[_]) => Some(x.ioMap) - case Left(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap) + val ioMap: Option[Map[Data, Data]] = instance.underlying match { + case Clone(x: ModuleClone[_]) => Some(x.ioMap) + case Proto(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap) case _ => None } if (isView(ret)) { @@ -342,15 +344,19 @@ private[chisel3] object Lookupable { type C = Instance[B] def definitionLookup[A](that: A => B, definition: Definition[A]): C = { val ret = that(definition.proto) - val cloned = new InstantiableClone(ret) - cloned._parent = definition.getInnerDataContext - new Instance(Right(cloned)) + val underlying = new InstantiableClone[B] { + val getProto = ret + lazy val _innerContext = definition + } + new Instance(Clone(underlying)) } def instanceLookup[A](that: A => B, instance: Instance[A]): C = { val ret = that(instance.proto) - val cloned = new InstantiableClone(ret) - cloned._parent = instance.getInnerDataContext - new Instance(Right(cloned)) + val underlying = new InstantiableClone[B] { + val getProto = ret + lazy val _innerContext = instance + } + new Instance(Clone(underlying)) } } diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala new file mode 100644 index 00000000..864cc8af --- /dev/null +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3.experimental.hierarchy + +import chisel3.internal.BaseModule.IsClone + +/** Represents the underlying implementation of a Definition or Instance */ +sealed trait Underlying[+T] + +/** A clone of a real implementation */ +final case class Clone[+T](isClone: IsClone[T]) extends Underlying[T] + +/** An actual implementation */ +final case class Proto[+T](proto: T) extends Underlying[T] diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 3761b371..55f89ae7 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -6,7 +6,7 @@ import scala.util.DynamicVariable import scala.collection.mutable.ArrayBuffer import chisel3._ import chisel3.experimental._ -import chisel3.experimental.hierarchy.Instance +import chisel3.experimental.hierarchy.{Instance, Clone} import chisel3.internal.firrtl._ import chisel3.internal.naming._ import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget} @@ -672,8 +672,8 @@ private[chisel3] object Builder extends LazyLogging { * (Note: Map is Iterable[Tuple2[_,_]] and thus excluded) */ def nameRecursively(prefix: String, nameMe: Any, namer: (HasId, String) => Unit): Unit = nameMe match { - case (id: Instance[_]) => id.cloned match { - case Right(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix) + case (id: Instance[_]) => id.underlying match { + case Clone(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix) case _ => } case (id: HasId) => namer(id, prefix) -- cgit v1.2.3 From d77fcf0478047fb61521fbe4b4a5a59a64b8445d Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Tue, 12 Oct 2021 01:30:25 +0800 Subject: remove_toBools --- core/src/main/scala/chisel3/Bits.scala | 6 ------ 1 file changed, 6 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala index 81b43483..58ec2585 100644 --- a/core/src/main/scala/chisel3/Bits.scala +++ b/core/src/main/scala/chisel3/Bits.scala @@ -309,12 +309,6 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi /** @group SourceInfoTransformMacro */ def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits - /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */ - final def toBools: Seq[Bool] = macro SourceInfoTransform.noArg - - @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5") - final def toBools(dummy: Int*): Seq[Bool] = macro SourceInfoWhiteboxTransform.noArgDummy - /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */ final def asBools: Seq[Bool] = macro SourceInfoTransform.noArg -- cgit v1.2.3 From a476329ef7b051aa480903cacd7d62ee46980c84 Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Tue, 30 Nov 2021 17:45:59 -0800 Subject: Bugfix - definition name index skipping with D/I (#2249) * Bugfix - definition name index skipping with D/I * Add tests to DefinitionSpec * Add failing test * Fix failing test * Update core/src/main/scala/chisel3/internal/Builder.scala Co-authored-by: Jack Koenig * whitespace * revert package private val Co-authored-by: Jack Koenig Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala | 2 +- core/src/main/scala/chisel3/internal/Builder.scala | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala index 2ac61807..c7b51072 100644 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala +++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala @@ -86,7 +86,7 @@ object Definition extends SourceInfoDoc { val dynamicContext = new DynamicContext(Nil) Builder.globalNamespace.copyTo(dynamicContext.globalNamespace) dynamicContext.inDefinition = true - val (ir, module) = Builder.build(Module(proto), dynamicContext) + val (ir, module) = Builder.build(Module(proto), dynamicContext, false) Builder.components ++= ir.components Builder.annotations ++= ir.annotations module._circuit = Builder.currentModule diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 55f89ae7..966e60d6 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -740,14 +740,16 @@ private[chisel3] object Builder extends LazyLogging { renames } - private [chisel3] def build[T <: BaseModule](f: => T, dynamicContext: DynamicContext): (Circuit, T) = { + private[chisel3] def build[T <: BaseModule](f: => T, dynamicContext: DynamicContext, forceModName: Boolean = true): (Circuit, T) = { dynamicContextVar.withValue(Some(dynamicContext)) { ViewParent // Must initialize the singleton in a Builder context or weird things can happen // in tiny designs/testcases that never access anything in chisel3.internal checkScalaVersion() logger.info("Elaborating design...") val mod = f - mod.forceName(None, mod.name, globalNamespace) + if (forceModName) { // This avoids definition name index skipping with D/I + mod.forceName(None, mod.name, globalNamespace) + } errors.checkpoint(logger) logger.info("Done elaborating.") -- cgit v1.2.3 From 392ea3c9b5b04e374eeb1bf3b0d87ac9fbf45513 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 1 Dec 2021 14:49:34 -0800 Subject: Require the chisel3 compiler plugin (#2271) As the chisel3 compiler plugin is now required, we can delete unused code for reflective autoclonetype as well as the noPluginTests.--- core/src/main/scala/chisel3/Aggregate.scala | 232 +-------------------- core/src/main/scala/chisel3/internal/Builder.scala | 49 ----- 2 files changed, 6 insertions(+), 275 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index 4cf427ff..7c7db1c6 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -1033,6 +1033,10 @@ package experimental { * }}} */ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { + assert(_usingPlugin, "The Chisel compiler plugin is now required for compiling Chisel code. " + + "Please see https://github.com/chipsalliance/chisel3#build-your-own-chisel-projects." + ) + override def className: String = this.getClass.getSimpleName match { case name if name.startsWith("$anon$") => "AnonymousBundle" // fallback for anonymous Bundle case case "" => "AnonymousBundle" // ditto, but on other platforms @@ -1109,16 +1113,6 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { */ protected def _usingPlugin: Boolean = false - // Memoize the outer instance for autoclonetype, especially where this is context-dependent - // (like the outer module or enclosing Bundles). - private var _outerInst: Option[Object] = None - - // For reflective autoclonetype, record possible candidates for outer instance. - // _outerInst should always take precedence, since it should be propagated from the original - // object which has the most accurate context. - private val _containingModule: Option[BaseModule] = if (_usingPlugin) None else Builder.currentModule - private val _containingBundles: Seq[Bundle] = if (_usingPlugin) Nil else Builder.updateBundleStack(this) - private def checkClone(clone: Bundle): Unit = { for ((name, field) <- elements) { if (clone.elements(name) eq field) { @@ -1142,224 +1136,10 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record { /** Implementation of cloneType using runtime reflection. This should _never_ be overridden or called in user-code * - * @note This is overridden by the compiler plugin (it is never called when using the plugin) + * @note This is overridden by the compiler plugin (this implementation is never called) */ protected def _cloneTypeImpl: Bundle = { - assert(Builder.allowReflectiveAutoCloneType, "reflective autoclonetype is disallowed, this should only happen in testing") - Builder.deprecated( - "The runtime reflection inference for cloneType (_cloneTypeImpl) is deprecated as of Chisel 3.5: " + - "Use the Compiler Plugin to infer cloneType" - ) - // This attempts to infer constructor and arguments to clone this Bundle subtype without - // requiring the user explicitly overriding cloneType. - import scala.language.existentials - import scala.reflect.runtime.universe._ - - val clazz = this.getClass - - def autoClonetypeError(desc: String): Nothing = - throw new AutoClonetypeException( - s"Unable to automatically infer cloneType on $clazz. " + - "cloneType is now implemented by the Chisel compiler plugin so please ensure you are using it in your build. " + - "If you cannot use the compiler plugin or you are using it and you still see this message, please file an issue and let us know. " + - s"For those not using the plugin, here is the 'runtime reflection' cloneType error message: $desc" - ) - - def validateClone(clone: Bundle, equivDiagnostic: String): Unit = { - if (!clone.typeEquivalent(this)) { - autoClonetypeError(s"Automatically cloned $clone not type-equivalent to base $this. " + equivDiagnostic) - } - checkClone(clone) - } - - val mirror = runtimeMirror(clazz.getClassLoader) - - val classSymbolOption = try { - Some(mirror.reflect(this).symbol) - } catch { - case e: scala.reflect.internal.Symbols#CyclicReference => None // Workaround for a scala bug - } - - val enclosingClassOption = (clazz.getEnclosingClass, classSymbolOption) match { - case (null, _) => None - case (_, Some(classSymbol)) if classSymbol.isStatic => None // allows support for members of companion objects - case (outerClass, _) => Some(outerClass) - } - - // For compatibility with pre-3.1, where null is tried as an argument to the constructor. - // This stores potential error messages which may be used later. - var outerClassError: Option[String] = None - - // Check if this is an inner class, and if so, try to get the outer instance - val outerClassInstance = enclosingClassOption.map { outerClass => - def canAssignOuterClass(x: Object) = outerClass.isAssignableFrom(x.getClass) - - val outerInstance = _outerInst match { - case Some(outerInstance) => outerInstance // use _outerInst if defined - case None => // determine outer instance if not already recorded - try { - // Prefer this if it works, but doesn't work in all cases, namely anonymous inner Bundles - val outer = clazz.getDeclaredField("$outer").get(this) - _outerInst = Some(outer) - outer - } catch { - case (_: NoSuchFieldException | _: IllegalAccessException) => - // Fallback using guesses based on common patterns - val allOuterCandidates = Seq( - _containingModule.toSeq, - _containingBundles - ).flatten.distinct - allOuterCandidates.filter(canAssignOuterClass(_)) match { - case outer :: Nil => - _outerInst = Some(outer) // record the guess for future use - outer - case Nil => // TODO: replace with fatal autoClonetypeError once compatibility period is dropped - outerClassError = Some(s"Unable to determine instance of outer class $outerClass," + - s" no candidates assignable to outer class types; examined $allOuterCandidates") - null - case candidates => // TODO: replace with fatal autoClonetypeError once compatibility period is dropped - outerClassError = Some(s"Unable to determine instance of outer class $outerClass," + - s" multiple possible candidates $candidates assignable to outer class type") - null - } - } - } - (outerClass, outerInstance) - } - - // If possible (constructor with no arguments), try Java reflection first - // This handles two cases that Scala reflection doesn't: - // 1. getting the ClassSymbol of a class with an anonymous outer class fails with a - // CyclicReference exception - // 2. invoking the constructor of an anonymous inner class seems broken (it expects the outer - // class as an argument, but fails because the number of arguments passed in is incorrect) - if (clazz.getConstructors.size == 1) { - var ctor = clazz.getConstructors.head - val argTypes = ctor.getParameterTypes.toList - val clone = (argTypes, outerClassInstance) match { - case (Nil, None) => // no arguments, no outer class, invoke constructor directly - Some(ctor.newInstance().asInstanceOf[this.type]) - case (argType :: Nil, Some((_, outerInstance))) => - if (outerInstance == null) { - Builder.deprecated(s"chisel3.1 autoclonetype failed, falling back to 3.0 behavior using null as the outer instance." + - s" Autoclonetype failure reason: ${outerClassError.get}", - Some(s"$clazz")) - Some(ctor.newInstance(outerInstance).asInstanceOf[this.type]) - } else if (argType isAssignableFrom outerInstance.getClass) { - Some(ctor.newInstance(outerInstance).asInstanceOf[this.type]) - } else { - None - } - case _ => None - - } - clone match { - case Some(clone) => - clone._outerInst = this._outerInst - validateClone(clone, "Constructor argument values were not inferred, ensure constructor is deterministic.") - return clone.asInstanceOf[this.type] - case None => - } - } - - // Get constructor parameters and accessible fields - val classSymbol = classSymbolOption.getOrElse(autoClonetypeError(s"scala reflection failed." + - " This is known to occur with inner classes on anonymous outer classes." + - " In those cases, autoclonetype only works with no-argument constructors, or you can define a custom cloneType.")) - - val decls = classSymbol.typeSignature.decls - val ctors = decls.collect { case meth: MethodSymbol if meth.isConstructor => meth } - if (ctors.size != 1) { - autoClonetypeError(s"found multiple constructors ($ctors)." + - " Either remove all but the default constructor, or define a custom cloneType method.") - } - val ctor = ctors.head - val ctorParamss = ctor.paramLists - val ctorParams = ctorParamss match { - case Nil => List() - case ctorParams :: Nil => ctorParams - case ctorParams :: ctorImplicits :: Nil => ctorParams ++ ctorImplicits - case _ => autoClonetypeError(s"internal error, unexpected ctorParamss = $ctorParamss") - } - val ctorParamsNames = ctorParams.map(_.name.toString) - - // Special case for anonymous inner classes: their constructor consists of just the outer class reference - // Scala reflection on anonymous inner class constructors seems broken - if (ctorParams.size == 1 && outerClassInstance.isDefined && - ctorParams.head.typeSignature == mirror.classSymbol(outerClassInstance.get._1).toType) { - // Fall back onto Java reflection - val ctors = clazz.getConstructors - require(ctors.size == 1) // should be consistent with Scala constructors - try { - val clone = ctors.head.newInstance(outerClassInstance.get._2).asInstanceOf[this.type] - clone._outerInst = this._outerInst - - validateClone(clone, "Outer class instance was inferred, ensure constructor is deterministic.") - return clone - } catch { - case e @ (_: java.lang.reflect.InvocationTargetException | _: IllegalArgumentException) => - autoClonetypeError(s"unexpected failure at constructor invocation, got $e.") - } - } - - // Get all the class symbols up to (but not including) Bundle and get all the accessors. - // (each ClassSymbol's decls only includes those declared in the class itself) - val bundleClassSymbol = mirror.classSymbol(classOf[Bundle]) - val superClassSymbols = classSymbol.baseClasses.takeWhile(_ != bundleClassSymbol) - val superClassDecls = superClassSymbols.map(_.typeSignature.decls).flatten - val accessors = superClassDecls.collect { case meth: MethodSymbol if meth.isParamAccessor => meth } - - // Get constructor argument values - // Check that all ctor params are immutable and accessible. Immutability is required to avoid - // potential subtle bugs (like values changing after cloning). - // This also generates better error messages (all missing elements shown at once) instead of - // failing at the use site one at a time. - val accessorsName = accessors.filter(_.isStable).map(_.name.toString) - val paramsDiff = ctorParamsNames.toSet -- accessorsName.toSet - if (!paramsDiff.isEmpty) { - autoClonetypeError(s"constructor has parameters (${paramsDiff.toList.sorted.mkString(", ")}) that are not both immutable and accessible." + - " Either make all parameters immutable and accessible (vals) so cloneType can be inferred, or define a custom cloneType method.") - } - - // Get all the argument values - val accessorsMap = accessors.map(accessor => accessor.name.toString -> accessor).toMap - val instanceReflect = mirror.reflect(this) - val ctorParamsNameVals = ctorParamsNames.map { - paramName => paramName -> instanceReflect.reflectMethod(accessorsMap(paramName)).apply() - } - - // Opportunistic sanity check: ensure any arguments of type Data is not bound - // (which could lead to data conflicts, since it's likely the user didn't know to re-bind them). - // This is not guaranteed to catch all cases (for example, Data in Tuples or Iterables). - val boundDataParamNames = ctorParamsNameVals.collect { - case (paramName, paramVal: Data) if paramVal.topBindingOpt.isDefined => paramName - } - if (boundDataParamNames.nonEmpty) { - autoClonetypeError(s"constructor parameters (${boundDataParamNames.sorted.mkString(", ")}) have values that are hardware types, which is likely to cause subtle errors." + - " Use chisel types instead: use the value before it is turned to a hardware type (with Wire(...), Reg(...), etc) or use chiselTypeOf(...) to extract the chisel type.") - } - - // Clone unbound parameters in case they are being used as bundle fields. - val ctorParamsVals = ctorParamsNameVals.map { - case (_, paramVal: Data) => paramVal.cloneTypeFull - case (_, paramVal) => paramVal - } - - // Invoke ctor - val classMirror = outerClassInstance match { - case Some((_, null)) => autoClonetypeError(outerClassError.get) // deals with the null hack for 3.0 compatibility - case Some((_, outerInstance)) => mirror.reflect(outerInstance).reflectClass(classSymbol) - case _ => mirror.reflectClass(classSymbol) - } - val clone = classMirror.reflectConstructor(ctor).apply(ctorParamsVals:_*).asInstanceOf[this.type] - clone._outerInst = this._outerInst - - validateClone(clone, - "Constructor argument values were inferred:" + - " ensure that variable names are consistent and have the same value throughout the constructor chain," + - " and that the constructor is deterministic." - ) - clone + throwException(s"Internal Error! This should have been implemented by the chisel3-plugin. Please file an issue against chisel3") } /** Default "pretty-print" implementation diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 966e60d6..71894887 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -343,9 +343,6 @@ private[chisel3] trait NamedComponent extends HasId { private[chisel3] class ChiselContext() { val idGen = new IdGen - // Record the Bundle instance, class name, method name, and reverse stack trace position of open Bundles - val bundleStack: ArrayBuffer[(Bundle, String, String, Int)] = ArrayBuffer() - // Records the different prefixes which have been scoped at this point in time var prefixStack: Prefix = Nil @@ -360,8 +357,6 @@ private[chisel3] class DynamicContext(val annotationSeq: AnnotationSeq) { val components = ArrayBuffer[Component]() val annotations = ArrayBuffer[ChiselAnnotation]() var currentModule: Option[BaseModule] = None - // This is only used for testing, it can be removed if the plugin becomes mandatory - var allowReflectiveAutoCloneType = true /** Contains a mapping from a elaborated module to their aspect * Set by [[ModuleAspect]] @@ -603,16 +598,6 @@ private[chisel3] object Builder extends LazyLogging { .getOrElse(false) } - // This should only be used for testing, must be true outside of Builder context - def allowReflectiveAutoCloneType: Boolean = { - dynamicContextVar.value - .map(_.allowReflectiveAutoCloneType) - .getOrElse(true) - } - def allowReflectiveAutoCloneType_=(value: Boolean): Unit = { - dynamicContext.allowReflectiveAutoCloneType = value - } - def forcedClock: Clock = currentClock.getOrElse( throwException("Error: No implicit clock.") ) @@ -632,40 +617,6 @@ private[chisel3] object Builder extends LazyLogging { pushCommand(cmd).id } - // Called when Bundle construction begins, used to record a stack of open Bundle constructors to - // record candidates for Bundle autoclonetype. This is a best-effort guess. - // Returns the current stack of open Bundles - // Note: elt will NOT have finished construction, its elements cannot be accessed - def updateBundleStack(elt: Bundle): Seq[Bundle] = { - val stackElts = Thread.currentThread().getStackTrace() - .reverse // so stack frame numbers are deterministic across calls - .dropRight(2) // discard Thread.getStackTrace and updateBundleStack - - // Determine where we are in the Bundle stack - val eltClassName = elt.getClass.getName - val eltStackPos = stackElts.map(_.getClassName).lastIndexOf(eltClassName) - - // Prune the existing Bundle stack of closed Bundles - // If we know where we are in the stack, discard frames above that - val stackEltsTop = if (eltStackPos >= 0) eltStackPos else stackElts.size - val pruneLength = chiselContext.get.bundleStack.reverse.prefixLength { case (_, cname, mname, pos) => - pos >= stackEltsTop || stackElts(pos).getClassName != cname || stackElts(pos).getMethodName != mname - } - chiselContext.get.bundleStack.trimEnd(pruneLength) - - // Return the stack state before adding the most recent bundle - val lastStack = chiselContext.get.bundleStack.map(_._1).toSeq - - // Append the current Bundle to the stack, if it's on the stack trace - if (eltStackPos >= 0) { - val stackElt = stackElts(eltStackPos) - chiselContext.get.bundleStack.append((elt, eltClassName, stackElt.getMethodName, eltStackPos)) - } - // Otherwise discard the stack frame, this shouldn't fail noisily - - lastStack - } - /** Recursively suggests names to supported "container" classes * Arbitrary nestings of supported classes are allowed so long as the * innermost element is of type HasId -- cgit v1.2.3 From 9dfee489b15642745174d191181ebf6f570db3ca Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Wed, 1 Dec 2021 16:09:34 -0800 Subject: Refactor Data.toString (#2197) Provides a more intuitive implementation of toString for Data. Utilizes the fact that the compiler plugin provides names earlier than Chisel had in the past so we can accurately guess the name of signals even in the currently elaborating module. Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/Aggregate.scala | 15 +++---- core/src/main/scala/chisel3/Bits.scala | 39 ++++++++--------- core/src/main/scala/chisel3/Clock.scala | 2 +- core/src/main/scala/chisel3/Data.scala | 51 ++++++++++++++-------- core/src/main/scala/chisel3/StrongEnum.scala | 15 ++++--- .../main/scala/chisel3/experimental/Analog.scala | 4 +- .../main/scala/chisel3/internal/firrtl/IR.scala | 15 ++++++- 7 files changed, 81 insertions(+), 60 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index 7c7db1c6..6c6d89c3 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -164,16 +164,14 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int) extends Aggregate with VecLike[T] { override def toString: String = { - val bindingString = topBindingOpt match { + topBindingOpt match { case Some(VecLitBinding(vecLitBinding)) => val contents = vecLitBinding.zipWithIndex.map { case ((data, lit), index) => s"$index=$lit" }.mkString(", ") - s"($contents)" - case _ => bindingToString + s"${sample_element.cloneType}[$length]($contents)" + case _ => stringAccessor(s"${sample_element.cloneType}[$length]") } - val elementType = sample_element.cloneType - s"$elementType[$length]$bindingString" } private[chisel3] override def typeEquivalent(that: Data): Boolean = that match { @@ -922,15 +920,14 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio * }}} */ override def toString: String = { - val bindingString = topBindingOpt match { + topBindingOpt match { case Some(BundleLitBinding(_)) => val contents = elements.toList.reverse.map { case (name, data) => s"$name=$data" }.mkString(", ") - s"($contents)" - case _ => bindingToString + s"$className($contents)" + case _ => stringAccessor(s"$className") } - s"$className$bindingString" } def elements: SeqMap[String, Data] diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala index 58ec2585..5ab04d13 100644 --- a/core/src/main/scala/chisel3/Bits.scala +++ b/core/src/main/scala/chisel3/Bits.scala @@ -399,11 +399,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi */ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[UInt] { override def toString: String = { - val bindingString = litOption match { - case Some(value) => s"($value)" - case _ => bindingToString + litOption match { + case Some(value) => s"UInt$width($value)" + case _ => stringAccessor(s"UInt$width") } - s"UInt$width$bindingString" } private[chisel3] override def typeEquivalent(that: Data): Boolean = @@ -773,11 +772,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U */ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[SInt] { override def toString: String = { - val bindingString = litOption match { - case Some(value) => s"($value)" - case _ => bindingToString + litOption match { + case Some(value) => s"SInt$width($value)" + case _ => stringAccessor(s"SInt$width") } - s"SInt$width$bindingString" } private[chisel3] override def typeEquivalent(that: Data): Boolean = @@ -1039,7 +1037,7 @@ object Reset { * super type due to Bool inheriting from abstract class UInt */ final class ResetType(private[chisel3] val width: Width = Width(1)) extends Element with Reset { - override def toString: String = s"Reset$bindingToString" + override def toString: String = stringAccessor("Reset") def cloneType: this.type = Reset().asInstanceOf[this.type] @@ -1081,7 +1079,7 @@ object AsyncReset { * asychronously reset registers. */ sealed class AsyncReset(private[chisel3] val width: Width = Width(1)) extends Element with Reset { - override def toString: String = s"AsyncReset$bindingToString" + override def toString: String = stringAccessor("AsyncReset") def cloneType: this.type = AsyncReset().asInstanceOf[this.type] @@ -1121,11 +1119,10 @@ sealed class AsyncReset(private[chisel3] val width: Width = Width(1)) extends El */ sealed class Bool() extends UInt(1.W) with Reset { override def toString: String = { - val bindingString = litToBooleanOption match { - case Some(value) => s"($value)" - case _ => bindingToString + litToBooleanOption match { + case Some(value) => s"Bool($value)" + case _ => stringAccessor("Bool") } - s"Bool$bindingString" } private[chisel3] override def cloneTypeWidth(w: Width): this.type = { @@ -1282,11 +1279,10 @@ package experimental { extends Bits(width) with Num[FixedPoint] with HasBinaryPoint { override def toString: String = { - val bindingString = litToDoubleOption match { - case Some(value) => s"($value)" - case _ => bindingToString + litToDoubleOption match { + case Some(value) => s"FixedPoint$width$binaryPoint($value)" + case _ => stringAccessor(s"FixedPoint$width$binaryPoint") } - s"FixedPoint$width$binaryPoint$bindingString" } private[chisel3] override def typeEquivalent(that: Data): Boolean = that match { @@ -1702,11 +1698,10 @@ package experimental { extends Bits(range.getWidth) with Num[Interval] with HasBinaryPoint { override def toString: String = { - val bindingString = litOption match { - case Some(value) => s"($value)" - case _ => bindingToString + litOption match { + case Some(value) => s"Interval$width($value)" + case _ => stringAccessor(s"Interval$width") } - s"Interval$width$bindingString" } private[chisel3] override def cloneTypeWidth(w: Width): this.type = diff --git a/core/src/main/scala/chisel3/Clock.scala b/core/src/main/scala/chisel3/Clock.scala index 0400697d..e4be6558 100644 --- a/core/src/main/scala/chisel3/Clock.scala +++ b/core/src/main/scala/chisel3/Clock.scala @@ -14,7 +14,7 @@ object Clock { // TODO: Document this. sealed class Clock(private[chisel3] val width: Width = Width(1)) extends Element { - override def toString: String = s"Clock$bindingToString" + override def toString: String = stringAccessor("Clock") def cloneType: this.type = Clock().asInstanceOf[this.type] diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala index 4ae29ce8..89908401 100644 --- a/core/src/main/scala/chisel3/Data.scala +++ b/core/src/main/scala/chisel3/Data.scala @@ -435,27 +435,44 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { _direction = Some(actualDirection) } + private[chisel3] def stringAccessor(chiselType: String): String = { + topBindingOpt match { + case None => chiselType + // Handle DontCares specially as they are "literal-like" but not actually literals + case Some(DontCareBinding()) => s"$chiselType(DontCare)" + case Some(topBinding) => + val binding: String = _bindingToString(topBinding) + val name = earlyName + val mod = parentNameOpt.map(_ + ".").getOrElse("") + + s"$mod$name: $binding[$chiselType]" + } + } + // User-friendly representation of the binding as a helper function for toString. // 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 = Try(topBindingOpt match { - case None => "" - case Some(OpBinding(enclosure, _)) => s"(OpResult in ${enclosure.desiredName})" - case Some(MemoryPortBinding(enclosure, _)) => s"(MemPort in ${enclosure.desiredName})" - case Some(PortBinding(enclosure)) if !enclosure.isClosed => s"(IO in unelaborated ${enclosure.desiredName})" - case Some(PortBinding(enclosure)) if enclosure.isClosed => - DataMirror.fullModulePorts(enclosure).find(_._2 eq this) match { - case Some((name, _)) => s"(IO $name in ${enclosure.desiredName})" - case None => s"(IO (unknown) in ${enclosure.desiredName})" - } - case Some(RegBinding(enclosure, _)) => s"(Reg in ${enclosure.desiredName})" - case Some(WireBinding(enclosure, _)) => s"(Wire in ${enclosure.desiredName})" - case Some(DontCareBinding()) => s"(DontCare)" - case Some(ElementLitBinding(litArg)) => s"(unhandled literal)" - case Some(BundleLitBinding(litMap)) => s"(unhandled bundle literal)" - case Some(VecLitBinding(litMap)) => s"(unhandled vec literal)" - }).getOrElse("") + @deprecated("This was never intended to be visible to user-defined types", "Chisel 3.5.0") + protected def bindingToString: String = _bindingToString(topBinding) + + private[chisel3] def _bindingToString(topBindingOpt: TopBinding): String = + topBindingOpt match { + case OpBinding(_, _) => "OpResult" + case MemoryPortBinding(_, _) => "MemPort" + case PortBinding(_) => "IO" + case RegBinding(_, _) => "Reg" + case WireBinding(_, _) => "Wire" + case DontCareBinding() => "(DontCare)" + case ElementLitBinding(litArg) => "(unhandled literal)" + case BundleLitBinding(litMap) => "(unhandled bundle literal)" + case VecLitBinding(litMap) => "(unhandled vec literal)" + case _ => "" + } + + private[chisel3] def earlyName: String = Arg.earlyLocalName(this) + + private[chisel3] def parentNameOpt: Option[String] = this._parent.map(_.name) // Return ALL elements at root of this type. // Contasts with flatten, which returns just Bits diff --git a/core/src/main/scala/chisel3/StrongEnum.scala b/core/src/main/scala/chisel3/StrongEnum.scala index 9ae4c889..fa420e80 100644 --- a/core/src/main/scala/chisel3/StrongEnum.scala +++ b/core/src/main/scala/chisel3/StrongEnum.scala @@ -72,17 +72,18 @@ import EnumAnnotations._ abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolean = true) extends Element { + + // Use getSimpleName instead of enumTypeName because for debugging purposes + // the fully qualified name isn't necessary (compared to for the + // Enum annotation), and it's more consistent with Bundle printing. override def toString: String = { - val bindingString = litOption match { + litOption match { case Some(value) => factory.nameOfValue(value) match { - case Some(name) => s"($value=$name)" - case None => s"($value=(invalid))" + case Some(name) => s"${factory.getClass.getSimpleName.init}($value=$name)" + case None => stringAccessor(s"${factory.getClass.getSimpleName.init}($value=(invalid))") } - case _ => bindingToString + case _ => stringAccessor(s"${factory.getClass.getSimpleName.init}") } - // Use getSimpleName instead of enumTypeName because for debugging purposes the fully qualified name isn't - // necessary (compared to for the Enum annotation), and it's more consistent with Bundle printing. - s"${factory.getClass.getSimpleName.init}$bindingString" } override def cloneType: this.type = factory().asInstanceOf[this.type] diff --git a/core/src/main/scala/chisel3/experimental/Analog.scala b/core/src/main/scala/chisel3/experimental/Analog.scala index 6cca81f5..e94bae2d 100644 --- a/core/src/main/scala/chisel3/experimental/Analog.scala +++ b/core/src/main/scala/chisel3/experimental/Analog.scala @@ -27,9 +27,7 @@ import scala.collection.mutable final class Analog private (private[chisel3] val width: Width) extends Element { require(width.known, "Since Analog is only for use in BlackBoxes, width must be known") - override def toString: String = { - s"Analog$width$bindingToString" - } + override def toString: String = stringAccessor(s"Analog$width") private[chisel3] override def typeEquivalent(that: Data): Boolean = that.isInstanceOf[Analog] && this.width == that.width diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index 1a06cd36..a352c96a 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -86,6 +86,19 @@ case class Node(id: HasId) extends Arg { } } +private[chisel3] object Arg { + def earlyLocalName(id: HasId): String = id.getOptionRef match { + 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(arg) => arg.name + case None => id match { + case data: Data => data._computeName(None, Some("?")).get + case _ => "?" + } + } +} + abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg { private[chisel3] def forcedWidth = widthArg.known private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth) @@ -196,7 +209,7 @@ case class Slot(imm: Node, name: String) extends Arg { if (immName.isEmpty) name else s"$immName.$name" } } -case class Index(imm: Arg, value: Arg) extends Arg { +case class Index(imm: Node, value: Arg) extends Arg { def name: String = s"[$value]" override def contextualName(ctx: Component): String = s"${imm.contextualName(ctx)}[${value.contextualName(ctx)}]" override def localName: String = s"${imm.localName}[${value.localName}]" -- cgit v1.2.3 From 08271081e4af2025fc6c6af97511fd110ef65e5c Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 8 Dec 2021 14:21:44 -0800 Subject: Implement DataViews for Seq and Tuple (#2277) * DataProducts for Seq and Tuple2-10 in DataProduct companion object * DataViews for Seq and Tuple 2-10 in DataView companion object * HWTuple2-10 Bundles in chisel3.experimental * Implicit conversions from Seq to Vec and Tuple to HWTuple in chisel3.experimental.conversions--- .../experimental/dataview/DataProduct.scala | 248 ++++++++++++++++++++- .../chisel3/experimental/dataview/DataView.scala | 239 +++++++++++++++++++- .../main/scala/chisel3/experimental/package.scala | 149 ++++++++++++- 3 files changed, 629 insertions(+), 7 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala index 55dd8505..438f97b8 100644 --- a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala +++ b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala @@ -3,7 +3,7 @@ package chisel3.experimental.dataview import chisel3.experimental.BaseModule -import chisel3.{Data, getRecursiveFields} +import chisel3.{Data, Vec, getRecursiveFields} import scala.annotation.implicitNotFound @@ -41,17 +41,24 @@ trait DataProduct[-A] { def dataSet(a: A): Data => Boolean = dataIterator(a, "").map(_._1).toSet } -/** Encapsulating object for automatically provided implementations of [[DataProduct]] +/** Low priority built-in implementations of [[DataProduct]] * - * @note DataProduct implementations provided in this object are available in the implicit scope + * @note This trait exists so that `dataDataProduct` can be lower priority than `seqDataProduct` to resolve ambiguity */ -object DataProduct { +sealed trait LowPriorityDataProduct { + /** [[DataProduct]] implementation for [[Data]] */ implicit val dataDataProduct: DataProduct[Data] = new DataProduct[Data] { def dataIterator(a: Data, path: String): Iterator[(Data, String)] = getRecursiveFields.lazily(a, path).iterator } +} +/** Encapsulating object for built-in implementations of [[DataProduct]] + * + * @note DataProduct implementations provided in this object are available in the implicit scope + */ +object DataProduct extends LowPriorityDataProduct { /** [[DataProduct]] implementation for [[BaseModule]] */ implicit val userModuleDataProduct: DataProduct[BaseModule] = new DataProduct[BaseModule] { def dataIterator(a: BaseModule, path: String): Iterator[(Data, String)] = { @@ -69,4 +76,237 @@ object DataProduct { e => e._id > a._id && e._id <= lastId } } + + /** [[DataProduct]] implementation for any `Seq[A]` where `A` has an implementation of `DataProduct`. */ + implicit def seqDataProduct[A : DataProduct]: DataProduct[Seq[A]] = new DataProduct[Seq[A]] { + def dataIterator(a: Seq[A], path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + a.iterator + .zipWithIndex + .flatMap { case (elt, idx) => + dpa.dataIterator(elt, s"$path[$idx]") + } + } + } + + /** [[DataProduct]] implementation for any [[Tuple2]] where each field has an implementation of `DataProduct`. */ + implicit def tuple2DataProduct[A : DataProduct, B : DataProduct]: DataProduct[(A, B)] = new DataProduct[(A, B)] { + def dataIterator(tup: (A, B), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val (a, b) = tup + dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") + } + } + + /** [[DataProduct]] implementation for any [[Tuple3]] where each field has an implementation of `DataProduct`. */ + implicit def tuple3DataProduct[A : DataProduct, B : DataProduct, C : DataProduct]: DataProduct[(A, B, C)] = + new DataProduct[(A, B, C)] { + def dataIterator(tup: (A, B, C), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val (a, b, c) = tup + dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") ++ dpc.dataIterator(c, s"$path._3") + } + } + + /** [[DataProduct]] implementation for any [[Tuple4]] where each field has an implementation of `DataProduct`. */ + implicit def tuple4DataProduct[A : DataProduct, B : DataProduct, C : DataProduct, D : DataProduct]: DataProduct[(A, B, C, D)] = + new DataProduct[(A, B, C, D)] { + def dataIterator(tup: (A, B, C, D), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val dpd = implicitly[DataProduct[D]] + val (a, b, c, d) = tup + dpa.dataIterator(a, s"$path._1") ++ + dpb.dataIterator(b, s"$path._2") ++ + dpc.dataIterator(c, s"$path._3") ++ + dpd.dataIterator(d, s"$path._4") + } + } + + /** [[DataProduct]] implementation for any [[Tuple5]] where each field has an implementation of `DataProduct`. */ + implicit def tuple5DataProduct[ + A : DataProduct, + B : DataProduct, + C : DataProduct, + D : DataProduct, + E : DataProduct]: DataProduct[(A, B, C, D, E)] = + new DataProduct[(A, B, C, D, E)] { + def dataIterator(tup: (A, B, C, D, E), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val dpd = implicitly[DataProduct[D]] + val dpe = implicitly[DataProduct[E]] + val (a, b, c, d, e) = tup + dpa.dataIterator(a, s"$path._1") ++ + dpb.dataIterator(b, s"$path._2") ++ + dpc.dataIterator(c, s"$path._3") ++ + dpd.dataIterator(d, s"$path._4") ++ + dpe.dataIterator(e, s"$path._5") + } + } + + /** [[DataProduct]] implementation for any [[Tuple6]] where each field has an implementation of `DataProduct`. */ + implicit def tuple6DataProduct[ + A : DataProduct, + B : DataProduct, + C : DataProduct, + D : DataProduct, + E : DataProduct, + F : DataProduct]: DataProduct[(A, B, C, D, E, F)] = + new DataProduct[(A, B, C, D, E, F)] { + def dataIterator(tup: (A, B, C, D, E, F), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val dpd = implicitly[DataProduct[D]] + val dpe = implicitly[DataProduct[E]] + val dpf = implicitly[DataProduct[F]] + val (a, b, c, d, e, f) = tup + dpa.dataIterator(a, s"$path._1") ++ + dpb.dataIterator(b, s"$path._2") ++ + dpc.dataIterator(c, s"$path._3") ++ + dpd.dataIterator(d, s"$path._4") ++ + dpe.dataIterator(e, s"$path._5") ++ + dpf.dataIterator(f, s"$path._6") + } + } + + /** [[DataProduct]] implementation for any [[Tuple7]] where each field has an implementation of `DataProduct`. */ + implicit def tuple7DataProduct[ + A : DataProduct, + B : DataProduct, + C : DataProduct, + D : DataProduct, + E : DataProduct, + F : DataProduct, + G : DataProduct]: DataProduct[(A, B, C, D, E, F, G)] = + new DataProduct[(A, B, C, D, E, F, G)] { + def dataIterator(tup: (A, B, C, D, E, F, G), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val dpd = implicitly[DataProduct[D]] + val dpe = implicitly[DataProduct[E]] + val dpf = implicitly[DataProduct[F]] + val dpg = implicitly[DataProduct[G]] + val (a, b, c, d, e, f, g) = tup + dpa.dataIterator(a, s"$path._1") ++ + dpb.dataIterator(b, s"$path._2") ++ + dpc.dataIterator(c, s"$path._3") ++ + dpd.dataIterator(d, s"$path._4") ++ + dpe.dataIterator(e, s"$path._5") ++ + dpf.dataIterator(f, s"$path._6") ++ + dpg.dataIterator(g, s"$path._7") + } + } + + /** [[DataProduct]] implementation for any [[Tuple8]] where each field has an implementation of `DataProduct`. */ + implicit def tuple8DataProduct[ + A : DataProduct, + B : DataProduct, + C : DataProduct, + D : DataProduct, + E : DataProduct, + F : DataProduct, + G : DataProduct, + H : DataProduct]: DataProduct[(A, B, C, D, E, F, G, H)] = + new DataProduct[(A, B, C, D, E, F, G, H)] { + def dataIterator(tup: (A, B, C, D, E, F, G, H), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val dpd = implicitly[DataProduct[D]] + val dpe = implicitly[DataProduct[E]] + val dpf = implicitly[DataProduct[F]] + val dpg = implicitly[DataProduct[G]] + val dph = implicitly[DataProduct[H]] + val (a, b, c, d, e, f, g, h) = tup + dpa.dataIterator(a, s"$path._1") ++ + dpb.dataIterator(b, s"$path._2") ++ + dpc.dataIterator(c, s"$path._3") ++ + dpd.dataIterator(d, s"$path._4") ++ + dpe.dataIterator(e, s"$path._5") ++ + dpf.dataIterator(f, s"$path._6") ++ + dpg.dataIterator(g, s"$path._7") ++ + dph.dataIterator(h, s"$path._8") + } + } + + /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */ + implicit def tuple9DataProduct[ + A : DataProduct, + B : DataProduct, + C : DataProduct, + D : DataProduct, + E : DataProduct, + F : DataProduct, + G : DataProduct, + H : DataProduct, + I : DataProduct]: DataProduct[(A, B, C, D, E, F, G, H, I)] = + new DataProduct[(A, B, C, D, E, F, G, H, I)] { + def dataIterator(tup: (A, B, C, D, E, F, G, H, I), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val dpd = implicitly[DataProduct[D]] + val dpe = implicitly[DataProduct[E]] + val dpf = implicitly[DataProduct[F]] + val dpg = implicitly[DataProduct[G]] + val dph = implicitly[DataProduct[H]] + val dpi = implicitly[DataProduct[I]] + val (a, b, c, d, e, f, g, h, i) = tup + dpa.dataIterator(a, s"$path._1") ++ + dpb.dataIterator(b, s"$path._2") ++ + dpc.dataIterator(c, s"$path._3") ++ + dpd.dataIterator(d, s"$path._4") ++ + dpe.dataIterator(e, s"$path._5") ++ + dpf.dataIterator(f, s"$path._6") ++ + dpg.dataIterator(g, s"$path._7") ++ + dph.dataIterator(h, s"$path._8") ++ + dpi.dataIterator(i, s"$path._9") + } + } + + /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */ + implicit def tuple10DataProduct[ + A : DataProduct, + B : DataProduct, + C : DataProduct, + D : DataProduct, + E : DataProduct, + F : DataProduct, + G : DataProduct, + H : DataProduct, + I : DataProduct, + J : DataProduct]: DataProduct[(A, B, C, D, E, F, G, H, I, J)] = + new DataProduct[(A, B, C, D, E, F, G, H, I, J)] { + def dataIterator(tup: (A, B, C, D, E, F, G, H, I, J), path: String): Iterator[(Data, String)] = { + val dpa = implicitly[DataProduct[A]] + val dpb = implicitly[DataProduct[B]] + val dpc = implicitly[DataProduct[C]] + val dpd = implicitly[DataProduct[D]] + val dpe = implicitly[DataProduct[E]] + val dpf = implicitly[DataProduct[F]] + val dpg = implicitly[DataProduct[G]] + val dph = implicitly[DataProduct[H]] + val dpi = implicitly[DataProduct[I]] + val dpj = implicitly[DataProduct[J]] + val (a, b, c, d, e, f, g, h, i, j) = tup + dpa.dataIterator(a, s"$path._1") ++ + dpb.dataIterator(b, s"$path._2") ++ + dpc.dataIterator(c, s"$path._3") ++ + dpd.dataIterator(d, s"$path._4") ++ + dpe.dataIterator(e, s"$path._5") ++ + dpf.dataIterator(f, s"$path._6") ++ + dpg.dataIterator(g, s"$path._7") ++ + dph.dataIterator(h, s"$path._8") ++ + dpi.dataIterator(i, s"$path._9") ++ + dpj.dataIterator(j, s"$path._10") + } + } } diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala index caf004c2..c17a5574 100644 --- a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala +++ b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala @@ -3,9 +3,12 @@ package chisel3.experimental.dataview import chisel3._ -import chisel3.internal.sourceinfo.SourceInfo -import scala.reflect.runtime.universe.WeakTypeTag +import chisel3.experimental.DataMirror.internal.chiselTypeClone +import chisel3.experimental.{HWTuple10, HWTuple2, HWTuple3, HWTuple4, HWTuple5, HWTuple6, HWTuple7, HWTuple8, HWTuple9} +import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} +import chisel3.ExplicitCompileOptions.Strict +import scala.reflect.runtime.universe.WeakTypeTag import annotation.implicitNotFound @@ -132,9 +135,241 @@ object DataView { case (b, a) => f(a, b).map(_.swap) } + // ****************************** Built-in Implementations of DataView ****************************** + // Sort of the "Standard library" implementations + /** All Chisel Data are viewable as their own type */ implicit def identityView[A <: Data](implicit sourceInfo: SourceInfo): DataView[A, A] = DataView[A, A](chiselTypeOf.apply, { case (x, y) => (x, y) }) + + /** Provides `DataView[Seq[A], Vec[B]]` for all `A` such that there exists `DataView[A, B]` */ + implicit def seqDataView[A : DataProduct, B <: Data](implicit dv: DataView[A, B], sourceInfo: SourceInfo): DataView[Seq[A], Vec[B]] = { + // TODO this would need a better way to determine the prototype for the Vec + DataView.mapping[Seq[A], Vec[B]]( + xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B]))(sourceInfo, Strict), // xs.head is not correct in general + { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } } + ) + } + + /** Provides implementations of [[DataView]] for [[Tuple2]] to [[HWTuple2]] */ + implicit def tuple2DataView[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], sourceInfo: SourceInfo + ): DataView[(T1, T2), HWTuple2[V1, V2]] = + DataView.mapping( + { case (a, b) => new HWTuple2(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType)}, + { case ((a, b), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2) + } + ) + + /** Provides implementations of [[DataView]] for [[Tuple3]] to [[HWTuple3]] */ + implicit def tuple3DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], sourceInfo: SourceInfo + ): DataView[(T1, T2, T3), HWTuple3[V1, V2, V3]] = + DataView.mapping( + { case (a, b, c) => new HWTuple3(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType)}, + { case ((a, b, c), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3) + } + ) + + /** Provides implementations of [[DataView]] for [[Tuple4]] to [[HWTuple4]] */ + implicit def tuple4DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], sourceInfo: SourceInfo + ): DataView[(T1, T2, T3, T4), HWTuple4[V1, V2, V3, V4]] = + DataView.mapping( + { case (a, b, c, d) => + new HWTuple4(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType + )}, + { case ((a, b, c, d), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3, + d.viewAs[V4] -> hwt._4) + } + ) + + /** Provides implementations of [[DataView]] for [[Tuple5]] to [[HWTuple5]] */ + implicit def tuple5DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5], sourceInfo: SourceInfo + ): DataView[(T1, T2, T3, T4, T5), HWTuple5[V1, V2, V3, V4, V5]] = { + DataView.mapping( + { case tup: Tuple5[T1, T2, T3, T4, T5] => + val (a, b, c, d, e) = tup + new HWTuple5(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType, + e.viewAs[V5].cloneType + ) + }, + { case ((a, b, c, d, e), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3, + d.viewAs[V4] -> hwt._4, + e.viewAs[V5] -> hwt._5) + } + ) + } + + /** Provides implementations of [[DataView]] for [[Tuple6]] to [[HWTuple6]] */ + implicit def tuple6DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, + V6 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], + v5: DataView[T5, V5], v6: DataView[T6, V6], + sourceInfo: SourceInfo + ): DataView[(T1, T2, T3, T4, T5, T6), HWTuple6[V1, V2, V3, V4, V5, V6]] = + DataView.mapping( + { case (a, b, c, d, e, f) => + new HWTuple6(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType, + e.viewAs[V5].cloneType, f.viewAs[V6].cloneType + ) + }, + { case ((a, b, c, d, e, f), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3, + d.viewAs[V4] -> hwt._4, + e.viewAs[V5] -> hwt._5, + f.viewAs[V6] -> hwt._6) + } + ) + + /** Provides implementations of [[DataView]] for [[Tuple7]] to [[HWTuple7]] */ + implicit def tuple7DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, + V6 <: Data, V7 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], + v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7], + sourceInfo: SourceInfo + ): DataView[(T1, T2, T3, T4, T5, T6, T7), HWTuple7[V1, V2, V3, V4, V5, V6, V7]] = + DataView.mapping( + { case (a, b, c, d, e, f, g) => + new HWTuple7(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType, + e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType + ) + }, + { case ((a, b, c, d, e, f, g), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3, + d.viewAs[V4] -> hwt._4, + e.viewAs[V5] -> hwt._5, + f.viewAs[V6] -> hwt._6, + g.viewAs[V7] -> hwt._7) + } + ) + + /** Provides implementations of [[DataView]] for [[Tuple8]] to [[HWTuple8]] */ + implicit def tuple8DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, + V6 <: Data, V7 <: Data, V8 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], + v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], + sourceInfo: SourceInfo + ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8), HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]] = + DataView.mapping( + { case (a, b, c, d, e, f, g, h) => + new HWTuple8(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType, + e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType, h.viewAs[V8].cloneType + ) + }, + { case ((a, b, c, d, e, f, g, h), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3, + d.viewAs[V4] -> hwt._4, + e.viewAs[V5] -> hwt._5, + f.viewAs[V6] -> hwt._6, + g.viewAs[V7] -> hwt._7, + h.viewAs[V8] -> hwt._8) + } + ) + + /** Provides implementations of [[DataView]] for [[Tuple9]] to [[HWTuple9]] */ + implicit def tuple9DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, + V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], + v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], + v9: DataView[T9, V9], + sourceInfo: SourceInfo + ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9), HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]] = + DataView.mapping( + { case (a, b, c, d, e, f, g, h, i) => + new HWTuple9(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType, + e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType, h.viewAs[V8].cloneType, + i.viewAs[V9].cloneType + ) + }, + { case ((a, b, c, d, e, f, g, h, i), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3, + d.viewAs[V4] -> hwt._4, + e.viewAs[V5] -> hwt._5, + f.viewAs[V6] -> hwt._6, + g.viewAs[V7] -> hwt._7, + h.viewAs[V8] -> hwt._8, + i.viewAs[V9] -> hwt._9) + } + ) + + /** Provides implementations of [[DataView]] for [[Tuple10]] to [[HWTuple10]] */ + implicit def tuple10DataView[ + T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, + T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct, T10 : DataProduct, + V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, + V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data, V10 <: Data + ]( + implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], + v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], + v9: DataView[T9, V9], v10: DataView[T10, V10], + sourceInfo: SourceInfo + ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]] = + DataView.mapping( + { case (a, b, c, d, e, f, g, h, i, j) => + new HWTuple10(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType, + e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType, h.viewAs[V8].cloneType, + i.viewAs[V9].cloneType, j.viewAs[V10].cloneType + ) + }, + { case ((a, b, c, d, e, f, g, h, i, j), hwt) => + Seq(a.viewAs[V1] -> hwt._1, + b.viewAs[V2] -> hwt._2, + c.viewAs[V3] -> hwt._3, + d.viewAs[V4] -> hwt._4, + e.viewAs[V5] -> hwt._5, + f.viewAs[V6] -> hwt._6, + g.viewAs[V7] -> hwt._7, + h.viewAs[V8] -> hwt._8, + i.viewAs[V9] -> hwt._9, + j.viewAs[V10] -> hwt._10) + } + ) } /** Factory methods for constructing non-total [[DataView]]s */ diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala index 0fc79487..5397a1c3 100644 --- a/core/src/main/scala/chisel3/experimental/package.scala +++ b/core/src/main/scala/chisel3/experimental/package.scala @@ -2,7 +2,8 @@ package chisel3 -import chisel3.internal.NamedComponent +import chisel3.ExplicitCompileOptions.Strict +import chisel3.experimental.DataMirror.internal.chiselTypeClone import chisel3.internal.sourceinfo.SourceInfo /** Package for experimental features, which may have their API changed, be removed, etc. @@ -166,4 +167,150 @@ package object experimental { val prefix = chisel3.internal.prefix // Use to remove prefixes not in provided scope val noPrefix = chisel3.internal.noPrefix + + // ****************************** Hardware equivalents of Scala Tuples ****************************** + // These are intended to be used via DataView + + /** [[Data]] equivalent of Scala's [[Tuple2]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple2` in + * `chisel3.experimental.conversions` + */ + final class HWTuple2[+A <: Data, +B <: Data] private[chisel3] (val _1: A, val _2: B) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple2(chiselTypeClone(_1), chiselTypeClone(_2)) + } + + /** [[Data]] equivalent of Scala's [[Tuple3]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple3` in + * `chisel3.experimental.conversions` + */ + final class HWTuple3[+A <: Data, +B <: Data, +C <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple3( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple4]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple4` in + * `chisel3.experimental.conversions` + */ + final class HWTuple4[+A <: Data, +B <: Data, +C <: Data, +D <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple4( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple5]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple5` in + * `chisel3.experimental.conversions` + */ + final class HWTuple5[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple5( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple6]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple6` in + * `chisel3.experimental.conversions` + */ + final class HWTuple6[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple6( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple7]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple7` in + * `chisel3.experimental.conversions` + */ + final class HWTuple7[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple7( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple8]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple8` in + * `chisel3.experimental.conversions` + */ + final class HWTuple8[ + +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data + ] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple8( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8) + ) + } + + /** [[Data]] equivalent of Scala's [[Tuple9]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple9` in + * `chisel3.experimental.conversions` + */ + final class HWTuple9[ + +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data, +I <: Data + ] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H, val _9: I + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple9( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8), chiselTypeClone(_9) + ) + } + + + /** [[Data]] equivalent of Scala's [[Tuple9]] + * + * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple9` in + * `chisel3.experimental.conversions` + */ + final class HWTuple10[ + +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data, +I <: Data, +J <: Data + ] private[chisel3] ( + val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H, val _9: I, val _10: J + ) extends Bundle()(Strict) { + // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually + override protected def _usingPlugin: Boolean = true + override protected def _cloneTypeImpl: Bundle = new HWTuple10( + chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5), + chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8), chiselTypeClone(_9), chiselTypeClone(_10) + ) + } } -- cgit v1.2.3 From 3f21bbb52363c3105f6a0ff961fa7a411dd0c7ab Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Thu, 9 Dec 2021 11:19:27 -0800 Subject: Better MonoConnect error messages (#2248) Co-authored-by: Megan Wachs --- core/src/main/scala/chisel3/Data.scala | 2 +- .../main/scala/chisel3/internal/MonoConnect.scala | 72 +++++++++++----------- 2 files changed, 38 insertions(+), 36 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala index 89908401..d67a3af6 100644 --- a/core/src/main/scala/chisel3/Data.scala +++ b/core/src/main/scala/chisel3/Data.scala @@ -494,7 +494,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { } catch { case MonoConnectException(message) => throwException( - s"Connection between sink ($this) and source ($that) failed @$message" + s"Connection between sink ($this) and source ($that) failed @: $message" ) } } else { diff --git a/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala index 5cbab329..6173fc91 100644 --- a/core/src/main/scala/chisel3/internal/MonoConnect.scala +++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala @@ -36,33 +36,35 @@ import chisel3.internal.sourceinfo.SourceInfo */ private[chisel3] object MonoConnect { + def formatName(data: Data) = s"""${data.earlyName} in ${data.parentNameOpt.getOrElse("(unknown)")}""" + // These are all the possible exceptions that can be thrown. // These are from element-level connection - def UnreadableSourceException = - MonoConnectException(": Source is unreadable from current module.") - def UnwritableSinkException = - MonoConnectException(": Sink is unwriteable by current module.") - def SourceEscapedWhenScopeException = - MonoConnectException(": Source has escaped the scope of the when in which it was constructed.") - def SinkEscapedWhenScopeException = - MonoConnectException(": Sink has escaped the scope of the when in which it was constructed.") + def UnreadableSourceException(sink: Data, source: Data) = + MonoConnectException(s"""${formatName(source)} cannot be read from module ${sink.parentNameOpt.getOrElse("(unknown)")}.""") + def UnwritableSinkException(sink: Data, source: Data) = + MonoConnectException(s"""${formatName(sink)} cannot be written from module ${source.parentNameOpt.getOrElse("(unknown)")}.""") + def SourceEscapedWhenScopeException(source: Data) = + MonoConnectException(s"Source ${formatName(source)} has escaped the scope of the when in which it was constructed.") + def SinkEscapedWhenScopeException(sink: Data) = + MonoConnectException(s"Sink ${formatName(sink)} has escaped the scope of the when in which it was constructed.") def UnknownRelationException = - MonoConnectException(": Sink or source unavailable to current module.") + MonoConnectException("Sink or source unavailable to current module.") // These are when recursing down aggregate types def MismatchedVecException = - MonoConnectException(": Sink and Source are different length Vecs.") + MonoConnectException("Sink and Source are different length Vecs.") def MissingFieldException(field: String) = - MonoConnectException(s": Source Record missing field ($field).") - def MismatchedException(sink: String, source: String) = - MonoConnectException(s": Sink ($sink) and Source ($source) have different types.") + MonoConnectException(s"Source Record missing field ($field).") + def MismatchedException(sink: Data, source: Data) = + MonoConnectException(s"Sink (${sink.cloneType.toString}) and Source (${source.cloneType.toString}) have different types.") def DontCareCantBeSink = - MonoConnectException(": DontCare cannot be a connection sink (LHS)") - def AnalogCantBeMonoSink = - MonoConnectException(": Analog cannot participate in a mono connection (sink - LHS)") - def AnalogCantBeMonoSource = - MonoConnectException(": Analog cannot participate in a mono connection (source - RHS)") - def AnalogMonoConnectionException = - MonoConnectException(": Analog cannot participate in a mono connection (source and sink)") + MonoConnectException("DontCare cannot be a connection sink") + def AnalogCantBeMonoSink(sink: Data) = + MonoConnectException(s"Sink ${formatName(sink)} of type Analog cannot participate in a mono connection (:=)") + def AnalogCantBeMonoSource(source: Data) = + MonoConnectException(s"Source ${formatName(source)} of type Analog cannot participate in a mono connection (:=)") + def AnalogMonoConnectionException(source: Data, sink: Data) = + MonoConnectException(s"Source ${formatName(source)} and sink ${formatName(sink)} of type Analog cannot participate in a mono connection (:=)") def checkWhenVisibility(x: Data): Boolean = { x.topBinding match { @@ -169,13 +171,13 @@ private[chisel3] object MonoConnect { // DontCare as a sink is illegal. case (DontCare, _) => throw DontCareCantBeSink // Analog is illegal in mono connections. - case (_: Analog, _:Analog) => throw AnalogMonoConnectionException + case (_: Analog, _:Analog) => throw AnalogMonoConnectionException(source, sink) // Analog is illegal in mono connections. - case (_: Analog, _) => throw AnalogCantBeMonoSink + case (_: Analog, _) => throw AnalogCantBeMonoSink(sink) // Analog is illegal in mono connections. - case (_, _: Analog) => throw AnalogCantBeMonoSource + case (_, _: Analog) => throw AnalogCantBeMonoSource(source) // Sink and source are different subtypes of data so fail - case (sink, source) => throw MismatchedException(sink.toString, source.toString) + case (sink, source) => throw MismatchedException(sink, source) } // This function (finally) issues the connection operation @@ -196,7 +198,7 @@ private[chisel3] object MonoConnect { val source = reify(_source) // If source has no location, assume in context module // This can occur if is a literal, unbound will error previously - val sink_mod: BaseModule = sink.topBinding.location.getOrElse(throw UnwritableSinkException) + val sink_mod: BaseModule = sink.topBinding.location.getOrElse(throw UnwritableSinkException(sink, source)) val source_mod: BaseModule = source.topBinding.location.getOrElse(context_mod) val sink_parent = Builder.retrieveParent(sink_mod, context_mod).getOrElse(None) @@ -206,11 +208,11 @@ private[chisel3] object MonoConnect { val source_direction = BindingDirection.from(source.topBinding, source.direction) if (!checkWhenVisibility(sink)) { - throw SinkEscapedWhenScopeException + throw SinkEscapedWhenScopeException(sink) } if (!checkWhenVisibility(source)) { - throw SourceEscapedWhenScopeException + throw SourceEscapedWhenScopeException(source) } // CASE: Context is same module that both left node and right node are in @@ -220,7 +222,7 @@ private[chisel3] object MonoConnect { // CURRENT MOD CURRENT MOD case (Output, _) => issueConnect(sink, source) case (Internal, _) => issueConnect(sink, source) - case (Input, _) => throw UnwritableSinkException + case (Input, _) => throw UnwritableSinkException(sink, source) } } @@ -238,11 +240,11 @@ private[chisel3] object MonoConnect { if (!(connectCompileOptions.dontAssumeDirectionality)) { issueConnect(sink, source) } else { - throw UnreadableSourceException + throw UnreadableSourceException(sink, source) } } case (Input, Output) if (!(connectCompileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink) - case (Input, _) => throw UnwritableSinkException + case (Input, _) => throw UnwritableSinkException(sink, source) } } @@ -253,8 +255,8 @@ private[chisel3] object MonoConnect { // SINK SOURCE // CHILD MOD CURRENT MOD case (Input, _) => issueConnect(sink, source) - case (Output, _) => throw UnwritableSinkException - case (Internal, _) => throw UnwritableSinkException + case (Output, _) => throw UnwritableSinkException(sink, source) + case (Internal, _) => throw UnwritableSinkException(sink, source) } } @@ -268,15 +270,15 @@ private[chisel3] object MonoConnect { // CHILD MOD CHILD MOD case (Input, Input) => issueConnect(sink, source) case (Input, Output) => issueConnect(sink, source) - case (Output, _) => throw UnwritableSinkException + case (Output, _) => throw UnwritableSinkException(sink, source) case (_, Internal) => { if (!(connectCompileOptions.dontAssumeDirectionality)) { issueConnect(sink, source) } else { - throw UnreadableSourceException + throw UnreadableSourceException(sink, source) } } - case (Internal, _) => throw UnwritableSinkException + case (Internal, _) => throw UnwritableSinkException(sink, source) } } -- cgit v1.2.3 From 630d05bdca90ec1c80eaaa7834e755f51095463d Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 10 Dec 2021 15:56:56 -0800 Subject: Add support for dynamic indexing on Vec identity views (#2298) --- core/src/main/scala/chisel3/Aggregate.scala | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index 6c6d89c3..dbde7068 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -3,7 +3,7 @@ package chisel3 import chisel3.experimental.VecLiterals.AddVecLiteralConstructor -import chisel3.experimental.dataview.{InvalidViewException, isView} +import chisel3.experimental.dataview.{InvalidViewException, isView, reifySingleData} import scala.collection.immutable.{SeqMap, VectorMap} import scala.collection.mutable.{HashSet, LinkedHashMap} @@ -258,9 +258,20 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int) def do_apply(p: UInt)(implicit compileOptions: CompileOptions): T = { requireIsHardware(this, "vec") requireIsHardware(p, "vec index") + + // Special handling for views if (isView(this)) { - throw InvalidViewException("Dynamic indexing of Views is not yet supported") + reifySingleData(this) match { + // Views complicate things a bit, but views that correspond exactly to an identical Vec can just forward the + // dynamic indexing to the target Vec + // In theory, we could still do this forwarding if the sample element were different by deriving a DataView + case Some(target: Vec[T @unchecked]) if this.length == target.length && + this.sample_element.typeEquivalent(target.sample_element) => + return target.do_apply(p) + case _ => throw InvalidViewException("Dynamic indexing of Views is not yet supported") + } } + val port = gen // Reconstruct the resolvedDirection (in Aggregate.bind), since it's not stored. -- cgit v1.2.3 From 55cb58877aca898f1ccae5edf29aeede9d1b71ba Mon Sep 17 00:00:00 2001 From: Øyvind Harboe Date: Sat, 11 Dec 2021 04:39:27 +0100 Subject: reduceTree() now operates on Seq (#2292) preserves input/output information of the type being reduced. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- core/src/main/scala/chisel3/Aggregate.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index dbde7068..600e2d11 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -338,11 +338,11 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int) def do_reduceTree(redOp: (T, T) => T, layerOp: (T) => T = (x: T) => x) (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : T = { require(!isEmpty, "Cannot apply reduction on a vec of size 0") - var curLayer = this + var curLayer : Seq[T] = this while (curLayer.length > 1) { - curLayer = VecInit(curLayer.grouped(2).map( x => + curLayer = curLayer.grouped(2).map( x => if (x.length == 1) layerOp(x(0)) else redOp(x(0), x(1)) - ).toSeq) + ).toSeq } curLayer(0) } -- cgit v1.2.3 From 21e324727e99f0bc124aaddea7fe294b4111c23a Mon Sep 17 00:00:00 2001 From: Aditya Naik Date: Tue, 14 Dec 2021 09:41:47 -0800 Subject: Make stuff in IR.scala package private (#2274) --- .../main/scala/chisel3/internal/firrtl/IR.scala | 85 +++++++++++----------- 1 file changed, 43 insertions(+), 42 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index a352c96a..3279e9b9 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -15,11 +15,11 @@ import scala.collection.immutable.NumericRange import scala.math.BigDecimal.RoundingMode -case class PrimOp(name: String) { +private[chisel3] case class PrimOp(name: String) { override def toString: String = name } -object PrimOp { +private[chisel3] object PrimOp { val AddOp = PrimOp("add") val SubOp = PrimOp("sub") val TailOp = PrimOp("tail") @@ -64,14 +64,14 @@ object PrimOp { val AsAsyncResetOp = PrimOp("asAsyncReset") } -abstract class Arg { +sealed private[chisel3] abstract class Arg { def localName: String = name def contextualName(ctx: Component): String = name def fullName(ctx: Component): String = contextualName(ctx) def name: String } -case class Node(id: HasId) extends Arg { +private[chisel3] case class Node(id: HasId) extends Arg { override def contextualName(ctx: Component): String = id.getOptionRef match { case Some(arg) => arg.contextualName(ctx) case None => id.instanceName @@ -99,7 +99,7 @@ private[chisel3] object Arg { } } -abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg { +private[chisel3] abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg { private[chisel3] def forcedWidth = widthArg.known private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth) override def contextualName(ctx: Component): String = name @@ -125,11 +125,11 @@ abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg { } } -case class ILit(n: BigInt) extends Arg { +private[chisel3] case class ILit(n: BigInt) extends Arg { def name: String = n.toString } -case class ULit(n: BigInt, w: Width) extends LitArg(n, w) { +private[chisel3] case class ULit(n: BigInt, w: Width) extends LitArg(n, w) { def name: String = "UInt" + width + "(\"h0" + num.toString(16) + "\")" def minWidth: Int = 1 max n.bitLength @@ -140,7 +140,7 @@ case class ULit(n: BigInt, w: Width) extends LitArg(n, w) { require(n >= 0, s"UInt literal ${n} is negative") } -case class SLit(n: BigInt, w: Width) extends LitArg(n, w) { +private[chisel3] case class SLit(n: BigInt, w: Width) extends LitArg(n, w) { def name: String = { val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n s"asSInt(${ULit(unsigned, width).name})" @@ -152,7 +152,7 @@ case class SLit(n: BigInt, w: Width) extends LitArg(n, w) { } } -case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { +private[chisel3] case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { def name: String = { val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n s"asFixedPoint(${ULit(unsigned, width).name}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})" @@ -164,7 +164,7 @@ case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n } } -case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { +private[chisel3] case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { def name: String = { val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n s"asInterval(${ULit(unsigned, width).name}, ${n}, ${n}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})" @@ -180,12 +180,12 @@ case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends Li } } -case class Ref(name: String) extends Arg +private[chisel3] case class Ref(name: String) extends Arg /** Arg for ports of Modules * @param mod the module this port belongs to * @param name the name of the port */ -case class ModuleIO(mod: BaseModule, name: String) extends Arg { +private[chisel3] case class ModuleIO(mod: BaseModule, name: String) extends Arg { override def contextualName(ctx: Component): String = if (mod eq ctx.id) name else s"${mod.getRef.name}.$name" } @@ -193,13 +193,13 @@ case class ModuleIO(mod: BaseModule, name: String) extends Arg { * @param mod The original module for which these ports are a clone * @param name the name of the module instance */ -case class ModuleCloneIO(mod: BaseModule, name: String) extends Arg { +private[chisel3] case class ModuleCloneIO(mod: BaseModule, name: String) extends Arg { override def localName = "" override def contextualName(ctx: Component): String = // NOTE: mod eq ctx.id only occurs in Target and Named-related APIs if (mod eq ctx.id) localName else name } -case class Slot(imm: Node, name: String) extends Arg { +private[chisel3] case class Slot(imm: Node, name: String) extends Arg { override def contextualName(ctx: Component): String = { val immName = imm.contextualName(ctx) if (immName.isEmpty) name else s"$immName.$name" @@ -209,7 +209,8 @@ case class Slot(imm: Node, name: String) extends Arg { if (immName.isEmpty) name else s"$immName.$name" } } -case class Index(imm: Node, value: Arg) extends Arg { + +private[chisel3] 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)}]" override def localName: String = s"${imm.localName}[${value.localName}]" @@ -773,47 +774,47 @@ sealed class IntervalRange( } } -abstract class Command { +private[chisel3] abstract class Command { def sourceInfo: SourceInfo } -abstract class Definition extends Command { +private[chisel3] abstract class Definition extends Command { def id: HasId def name: String = id.getRef.name } -case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition -case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command -case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition -case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition -case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition -case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition -case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition -case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition -case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition -case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command -case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command -case class AltBegin(sourceInfo: SourceInfo) extends Command -case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) extends Command -case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command -case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command -case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command -case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command -case class Stop(id: stop.Stop, sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Definition -case class Port(id: Data, dir: SpecifiedDirection) -case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition -object Formal extends Enumeration { +private[chisel3] case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition +private[chisel3] case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command +private[chisel3] case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition +private[chisel3] case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition +private[chisel3] case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition +private[chisel3] case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition +private[chisel3] case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition +private[chisel3] case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition +private[chisel3] case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition +private[chisel3] case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command +private[chisel3] case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command +private[chisel3] case class AltBegin(sourceInfo: SourceInfo) extends Command +private[chisel3] case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) extends Command +private[chisel3] case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +private[chisel3] case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command +private[chisel3] case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command +private[chisel3] case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +private[chisel3] case class Stop(id: stop.Stop, sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Definition +private[chisel3] case class Port(id: Data, dir: SpecifiedDirection) +private[chisel3] case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition +private[chisel3] object Formal extends Enumeration { val Assert = Value("assert") val Assume = Value("assume") val Cover = Value("cover") } -case class Verification[T <: VerificationStatement](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg, +private[chisel3] case class Verification[T <: VerificationStatement](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg, predicate: Arg, message: String) extends Definition -abstract class Component extends Arg { +private[chisel3] abstract class Component extends Arg { def id: BaseModule def name: String def ports: Seq[Port] } -case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component -case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component +private[chisel3] case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component +private[chisel3] case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) { def firrtlAnnotations: Iterable[Annotation] = annotations.flatMap(_.toFirrtl.update(renames)) -- cgit v1.2.3 From 7e8ec50376f852d5ab35d7609d986c7e4128abb1 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Wed, 15 Dec 2021 08:40:14 +0800 Subject: deprecate getModulePorts (#2284) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- core/src/main/scala/chisel3/package.scala | 1 + 1 file changed, 1 insertion(+) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala index 68e482dd..faca3ae4 100644 --- a/core/src/main/scala/chisel3/package.scala +++ b/core/src/main/scala/chisel3/package.scala @@ -221,6 +221,7 @@ package object chisel3 { def getDataElements(a: Aggregate): Seq[Element] = { a.allElements } + @deprecated("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] = m.getPorts class BindingException(message: String) extends ChiselException(message) -- cgit v1.2.3 From 4ff431bb5c7978c9915bcd6080a4f27ef12ae607 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 15 Dec 2021 13:02:12 -0800 Subject: Restore Port to public API and deprecate (#2302) Also clean up deprecation warnings for replacement APIs and add clarifying ScalaDoc.--- core/src/main/scala/chisel3/BlackBox.scala | 3 ++ core/src/main/scala/chisel3/Data.scala | 55 ++++++++++++++++++++-- core/src/main/scala/chisel3/RawModule.scala | 8 ++-- .../scala/chisel3/internal/firrtl/Converter.scala | 3 +- .../main/scala/chisel3/internal/firrtl/IR.scala | 9 +++- 5 files changed, 68 insertions(+), 10 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/BlackBox.scala b/core/src/main/scala/chisel3/BlackBox.scala index 38b08193..ec5de0cd 100644 --- a/core/src/main/scala/chisel3/BlackBox.scala +++ b/core/src/main/scala/chisel3/BlackBox.scala @@ -8,6 +8,7 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl._ import chisel3.internal.throwException import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} +import scala.annotation.nowarn package internal { @@ -61,6 +62,7 @@ package experimental { * }}} * @note The parameters API is experimental and may change */ + @nowarn("msg=class Port") // delete when Port becomes private abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Param]) extends BaseBlackBox { private[chisel3] override def generateComponent(): Option[Component] = { require(!_closed, "Can't generate module more than once") @@ -134,6 +136,7 @@ package experimental { * }}} * @note The parameters API is experimental and may change */ +@nowarn("msg=class Port") // delete when Port becomes private abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param])(implicit compileOptions: CompileOptions) extends BaseBlackBox { // Find a Record port named "io" for purposes of stripping the prefix diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala index d67a3af6..2bca5f98 100644 --- a/core/src/main/scala/chisel3/Data.scala +++ b/core/src/main/scala/chisel3/Data.scala @@ -154,13 +154,58 @@ package experimental { **/ def checkTypeEquivalence(x: Data, y: Data): Boolean = x.typeEquivalent(y) - // Returns the top-level module ports - // TODO: maybe move to something like Driver or DriverUtils, since this is mainly for interacting - // with compiled artifacts (vs. elaboration-time reflection)? + /** Returns the ports of a module + * {{{ + * class MyModule extends Module { + * val io = IO(new Bundle { + * val in = Input(UInt(8.W)) + * val out = Output(Vec(2, UInt(8.W))) + * }) + * val extra = IO(Input(UInt(8.W))) + * val delay = RegNext(io.in) + * io.out(0) := delay + * io.out(1) := delay + extra + * } + * val mod = Module(new MyModule) + * DataMirror.modulePorts(mod) + * // returns: Seq( + * // "clock" -> mod.clock, + * // "reset" -> mod.reset, + * // "io" -> mod.io, + * // "extra" -> mod.extra + * // ) + * }}} + */ def modulePorts(target: BaseModule): Seq[(String, Data)] = target.getChiselPorts - /** Returns all module ports with underscore-qualified names - * return includes [[Module.clock]] and [[Module.reset]] + /** Returns a recursive representation of a module's ports with underscore-qualified names + * {{{ + * class MyModule extends Module { + * val io = IO(new Bundle { + * val in = Input(UInt(8.W)) + * val out = Output(Vec(2, UInt(8.W))) + * }) + * val extra = IO(Input(UInt(8.W))) + * val delay = RegNext(io.in) + * io.out(0) := delay + * io.out(1) := delay + extra + * } + * val mod = Module(new MyModule) + * DataMirror.fullModulePorts(mod) + * // returns: Seq( + * // "clock" -> mod.clock, + * // "reset" -> mod.reset, + * // "io" -> mod.io, + * // "io_out" -> mod.io.out, + * // "io_out_0" -> mod.io.out(0), + * // "io_out_1" -> mod.io.out(1), + * // "io_in" -> mod.io.in, + * // "extra" -> mod.extra + * // ) + * }}} + * @note The returned ports are redundant. An [[Aggregate]] port will be present along with all + * of its children. + * @see [[DataMirror.modulePorts]] for a non-recursive representation of the ports. */ def fullModulePorts(target: BaseModule): Seq[(String, Data)] = { def getPortNames(name: String, data: Data): Seq[(String, Data)] = Seq(name -> data) ++ (data match { diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index d8781ee0..e977d918 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -5,6 +5,7 @@ package chisel3 import scala.collection.mutable.{ArrayBuffer, HashMap} import scala.util.Try import scala.language.experimental.macros +import scala.annotation.nowarn import chisel3.experimental.BaseModule import chisel3.internal._ import chisel3.internal.BaseModule.{ModuleClone, InstanceClone} @@ -17,6 +18,7 @@ import _root_.firrtl.annotations.{IsModule, ModuleTarget} * This abstract base class is a user-defined module which does not include implicit clock and reset and supports * multiple IO() declarations. */ +@nowarn("msg=class Port") // delete when Port becomes private abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends BaseModule { // @@ -35,10 +37,10 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) // // Other Internal Functions // - // For debuggers/testers, TODO: refactor out into proper public API private var _firrtlPorts: Option[Seq[firrtl.Port]] = None - @deprecated("Use DataMirror.fullModulePorts instead. this API will be removed in Chisel 3.6", "Chisel 3.5") - lazy val getPorts = _firrtlPorts.get + + @deprecated("Use DataMirror.modulePorts instead. this API will be removed in Chisel 3.6", "Chisel 3.5") + lazy val getPorts: Seq[Port] = _firrtlPorts.get val compileOptions = moduleCompileOptions diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index 1dc52823..ac784882 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala @@ -7,10 +7,11 @@ import chisel3.internal.sourceinfo.{NoSourceInfo, SourceInfo, SourceLine, Unloca import firrtl.{ir => fir} import chisel3.internal.{HasId, castToInt, throwException} -import scala.annotation.tailrec +import scala.annotation.{nowarn, tailrec} import scala.collection.immutable.Queue import scala.collection.immutable.LazyList // Needed for 2.12 alias +@nowarn("msg=class Port") // delete when Port becomes private private[chisel3] object Converter { // TODO modeled on unpack method on Printable, refactor? def unpack(pable: Printable, ctx: Component): (String, Seq[Arg]) = pable match { diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index 3279e9b9..e3ea42c3 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -13,6 +13,7 @@ import _root_.firrtl.annotations.Annotation import scala.collection.immutable.NumericRange import scala.math.BigDecimal.RoundingMode +import scala.annotation.nowarn private[chisel3] case class PrimOp(name: String) { @@ -789,6 +790,7 @@ private[chisel3] case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: private[chisel3] case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition private[chisel3] case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition private[chisel3] case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition +@nowarn("msg=class Port") // delete when Port becomes private private[chisel3] case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition private[chisel3] case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command private[chisel3] case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command @@ -799,7 +801,9 @@ private[chisel3] case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2 private[chisel3] case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command private[chisel3] case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command private[chisel3] case class Stop(id: stop.Stop, sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Definition -private[chisel3] case class Port(id: Data, dir: SpecifiedDirection) +// Note this is just deprecated which will cause deprecation warnings, use @nowarn +@deprecated("This API should never have been public, for Module port reflection, use DataMirror.modulePorts", "Chisel 3.5") +case class Port(id: Data, dir: SpecifiedDirection) private[chisel3] case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition private[chisel3] object Formal extends Enumeration { val Assert = Value("assert") @@ -808,12 +812,15 @@ private[chisel3] object Formal extends Enumeration { } private[chisel3] case class Verification[T <: VerificationStatement](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg, predicate: Arg, message: String) extends Definition +@nowarn("msg=class Port") // delete when Port becomes private private[chisel3] abstract class Component extends Arg { def id: BaseModule def name: String def ports: Seq[Port] } +@nowarn("msg=class Port") // delete when Port becomes private private[chisel3] case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component +@nowarn("msg=class Port") // delete when Port becomes private private[chisel3] case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) { -- cgit v1.2.3 From 109b4d8629beb62f7516ca14295258b4131f5849 Mon Sep 17 00:00:00 2001 From: Chick Markley Date: Fri, 17 Dec 2021 10:13:54 -0800 Subject: Improve exception message for aliased bundle fields (#2304) - Shows groups of field names that share a common id (i.e. aliased) - Show, as much as possible, them in the order that fields appear in bundle - Updated BundleSpec's relevant tests Co-authored-by: Megan Wachs Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/Aggregate.scala | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index 600e2d11..db354e1f 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -29,7 +29,26 @@ sealed abstract class Aggregate extends Data { val resolvedDirection = SpecifiedDirection.fromParent(parentDirection, specifiedDirection) val duplicates = getElements.groupBy(identity).collect { case (x, elts) if elts.size > 1 => x } if (!duplicates.isEmpty) { - throw new AliasedAggregateFieldException(s"Aggregate $this contains aliased fields $duplicates") + this match { + case b: Record => + // show groups of names of fields with duplicate id's + // The sorts make the displayed order of fields deterministic and matching the order of occurrence in the Bundle. + // It's a bit convoluted but happens rarely and makes the error message easier to understand + val dupNames = duplicates.toSeq.sortBy(_._id).map { duplicate => + b.elements + .collect { case x if x._2._id == duplicate._id => x } + .toSeq.sortBy(_._2._id) + .map(_._1).reverse + .mkString("(", ",", ")") + }.mkString(",") + throw new AliasedAggregateFieldException( + s"${b.className} contains aliased fields named ${dupNames}" + ) + case _ => + throw new AliasedAggregateFieldException( + s"Aggregate ${this.getClass} contains aliased fields $duplicates ${duplicates.mkString(",")}" + ) + } } for (child <- getElements) { child.bind(ChildBinding(this), resolvedDirection) -- cgit v1.2.3 From f50f74f583fba7b98e550c440df091e559ce32b8 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 17 Dec 2021 17:17:03 -0800 Subject: Revert "Make stuff in IR.scala package private (#2274)" (#2308) This reverts commit 21e324727e99f0bc124aaddea7fe294b4111c23a. Note that I am keeping the change making Arg sealed.--- .../main/scala/chisel3/internal/firrtl/IR.scala | 84 +++++++++++----------- 1 file changed, 42 insertions(+), 42 deletions(-) (limited to 'core/src') diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index e3ea42c3..68f5f18e 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -16,11 +16,11 @@ import scala.math.BigDecimal.RoundingMode import scala.annotation.nowarn -private[chisel3] case class PrimOp(name: String) { +case class PrimOp(name: String) { override def toString: String = name } -private[chisel3] object PrimOp { +object PrimOp { val AddOp = PrimOp("add") val SubOp = PrimOp("sub") val TailOp = PrimOp("tail") @@ -65,14 +65,14 @@ private[chisel3] object PrimOp { val AsAsyncResetOp = PrimOp("asAsyncReset") } -sealed private[chisel3] abstract class Arg { +sealed abstract class Arg { def localName: String = name def contextualName(ctx: Component): String = name def fullName(ctx: Component): String = contextualName(ctx) def name: String } -private[chisel3] case class Node(id: HasId) extends Arg { +case class Node(id: HasId) extends Arg { override def contextualName(ctx: Component): String = id.getOptionRef match { case Some(arg) => arg.contextualName(ctx) case None => id.instanceName @@ -87,7 +87,7 @@ private[chisel3] case class Node(id: HasId) extends Arg { } } -private[chisel3] object Arg { +object Arg { def earlyLocalName(id: HasId): String = id.getOptionRef match { case Some(Index(Node(imm), Node(value))) => s"${earlyLocalName(imm)}[${earlyLocalName(imm)}]" case Some(Index(Node(imm), arg)) => s"${earlyLocalName(imm)}[${arg.localName}]" @@ -100,7 +100,7 @@ private[chisel3] object Arg { } } -private[chisel3] abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg { +abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg { private[chisel3] def forcedWidth = widthArg.known private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth) override def contextualName(ctx: Component): String = name @@ -126,11 +126,11 @@ private[chisel3] abstract class LitArg(val num: BigInt, widthArg: Width) extends } } -private[chisel3] case class ILit(n: BigInt) extends Arg { +case class ILit(n: BigInt) extends Arg { def name: String = n.toString } -private[chisel3] case class ULit(n: BigInt, w: Width) extends LitArg(n, w) { +case class ULit(n: BigInt, w: Width) extends LitArg(n, w) { def name: String = "UInt" + width + "(\"h0" + num.toString(16) + "\")" def minWidth: Int = 1 max n.bitLength @@ -141,7 +141,7 @@ private[chisel3] case class ULit(n: BigInt, w: Width) extends LitArg(n, w) { require(n >= 0, s"UInt literal ${n} is negative") } -private[chisel3] case class SLit(n: BigInt, w: Width) extends LitArg(n, w) { +case class SLit(n: BigInt, w: Width) extends LitArg(n, w) { def name: String = { val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n s"asSInt(${ULit(unsigned, width).name})" @@ -153,7 +153,7 @@ private[chisel3] case class SLit(n: BigInt, w: Width) extends LitArg(n, w) { } } -private[chisel3] case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { +case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { def name: String = { val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n s"asFixedPoint(${ULit(unsigned, width).name}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})" @@ -165,7 +165,7 @@ private[chisel3] case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) } } -private[chisel3] case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { +case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { def name: String = { val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n s"asInterval(${ULit(unsigned, width).name}, ${n}, ${n}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})" @@ -181,12 +181,12 @@ private[chisel3] case class IntervalLit(n: BigInt, w: Width, binaryPoint: Binary } } -private[chisel3] case class Ref(name: String) extends Arg +case class Ref(name: String) extends Arg /** Arg for ports of Modules * @param mod the module this port belongs to * @param name the name of the port */ -private[chisel3] case class ModuleIO(mod: BaseModule, name: String) extends Arg { +case class ModuleIO(mod: BaseModule, name: String) extends Arg { override def contextualName(ctx: Component): String = if (mod eq ctx.id) name else s"${mod.getRef.name}.$name" } @@ -194,13 +194,13 @@ private[chisel3] case class ModuleIO(mod: BaseModule, name: String) extends Arg * @param mod The original module for which these ports are a clone * @param name the name of the module instance */ -private[chisel3] case class ModuleCloneIO(mod: BaseModule, name: String) extends Arg { +case class ModuleCloneIO(mod: BaseModule, name: String) extends Arg { override def localName = "" override def contextualName(ctx: Component): String = // NOTE: mod eq ctx.id only occurs in Target and Named-related APIs if (mod eq ctx.id) localName else name } -private[chisel3] case class Slot(imm: Node, name: String) extends Arg { +case class Slot(imm: Node, name: String) extends Arg { override def contextualName(ctx: Component): String = { val immName = imm.contextualName(ctx) if (immName.isEmpty) name else s"$immName.$name" @@ -211,7 +211,7 @@ private[chisel3] case class Slot(imm: Node, name: String) extends Arg { } } -private[chisel3] case class Index(imm: Arg, value: Arg) extends Arg { +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)}]" override def localName: String = s"${imm.localName}[${value.localName}]" @@ -775,53 +775,53 @@ sealed class IntervalRange( } } -private[chisel3] abstract class Command { +abstract class Command { def sourceInfo: SourceInfo } -private[chisel3] abstract class Definition extends Command { +abstract class Definition extends Command { def id: HasId def name: String = id.getRef.name } -private[chisel3] case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition -private[chisel3] case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command -private[chisel3] case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition -private[chisel3] case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition -private[chisel3] case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition -private[chisel3] case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition -private[chisel3] case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition -private[chisel3] case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition +case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition +case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command +case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition +case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition +case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition +case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition +case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition +case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition @nowarn("msg=class Port") // delete when Port becomes private -private[chisel3] case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition -private[chisel3] case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command -private[chisel3] case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command -private[chisel3] case class AltBegin(sourceInfo: SourceInfo) extends Command -private[chisel3] case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) extends Command -private[chisel3] case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command -private[chisel3] case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command -private[chisel3] case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command -private[chisel3] case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command -private[chisel3] case class Stop(id: stop.Stop, sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Definition +case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition +case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command +case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command +case class AltBegin(sourceInfo: SourceInfo) extends Command +case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) extends Command +case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command +case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command +case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command +case class Stop(id: stop.Stop, sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Definition // Note this is just deprecated which will cause deprecation warnings, use @nowarn @deprecated("This API should never have been public, for Module port reflection, use DataMirror.modulePorts", "Chisel 3.5") case class Port(id: Data, dir: SpecifiedDirection) -private[chisel3] case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition -private[chisel3] object Formal extends Enumeration { +case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition +object Formal extends Enumeration { val Assert = Value("assert") val Assume = Value("assume") val Cover = Value("cover") } -private[chisel3] case class Verification[T <: VerificationStatement](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg, +case class Verification[T <: VerificationStatement](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg, predicate: Arg, message: String) extends Definition @nowarn("msg=class Port") // delete when Port becomes private -private[chisel3] abstract class Component extends Arg { +abstract class Component extends Arg { def id: BaseModule def name: String def ports: Seq[Port] } @nowarn("msg=class Port") // delete when Port becomes private -private[chisel3] case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component +case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component @nowarn("msg=class Port") // delete when Port becomes private -private[chisel3] case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component +case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) { def firrtlAnnotations: Iterable[Annotation] = annotations.flatMap(_.toFirrtl.update(renames)) -- cgit v1.2.3