summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorJack2021-12-18 08:27:38 +0000
committerJack2021-12-18 08:27:38 +0000
commitdd9ad534771247ac16eaa47eb9794102736b5102 (patch)
treed4566d317cb8526b79017de1e438aea8217dd1d4 /core/src
parent440edc4436fb3a8a4175ae425a0d31c4997ee60f (diff)
parentf50f74f583fba7b98e550c440df091e559ce32b8 (diff)
Merge branch 'master' into 3.5-release
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/scala/chisel3/Aggregate.scala287
-rw-r--r--core/src/main/scala/chisel3/Assert.scala92
-rw-r--r--core/src/main/scala/chisel3/Bits.scala204
-rw-r--r--core/src/main/scala/chisel3/BlackBox.scala3
-rw-r--r--core/src/main/scala/chisel3/Clock.scala10
-rw-r--r--core/src/main/scala/chisel3/Data.scala133
-rw-r--r--core/src/main/scala/chisel3/Mem.scala2
-rw-r--r--core/src/main/scala/chisel3/Module.scala83
-rw-r--r--core/src/main/scala/chisel3/Num.scala5
-rw-r--r--core/src/main/scala/chisel3/Printf.scala3
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala20
-rw-r--r--core/src/main/scala/chisel3/Reg.scala4
-rw-r--r--core/src/main/scala/chisel3/SeqUtils.scala2
-rw-r--r--core/src/main/scala/chisel3/StrongEnum.scala23
-rw-r--r--core/src/main/scala/chisel3/VerificationStatement.scala236
-rw-r--r--core/src/main/scala/chisel3/When.scala9
-rw-r--r--core/src/main/scala/chisel3/experimental/Analog.scala4
-rw-r--r--core/src/main/scala/chisel3/experimental/Trace.scala69
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala248
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/DataView.scala239
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala23
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala112
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala54
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala2
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala31
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala102
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala14
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala150
-rw-r--r--core/src/main/scala/chisel3/experimental/verification/package.scala60
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala92
-rw-r--r--core/src/main/scala/chisel3/internal/MonoConnect.scala72
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/Converter.scala7
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala27
-rw-r--r--core/src/main/scala/chisel3/internal/plugin/package.scala19
-rw-r--r--core/src/main/scala/chisel3/internal/prefix.scala4
-rw-r--r--core/src/main/scala/chisel3/package.scala26
36 files changed, 1703 insertions, 768 deletions
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala
index 17e46cb3..db354e1f 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}
@@ -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)
@@ -54,7 +73,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
@@ -164,16 +183,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 {
@@ -260,9 +277,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.
@@ -329,11 +357,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)
}
@@ -922,15 +950,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]
@@ -1033,6 +1060,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 +1140,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,220 +1163,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")
- // 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/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/Bits.scala b/core/src/main/scala/chisel3/Bits.scala
index 670f6e7a..5ab04d13 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,10 @@ 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 asBools: Seq[Bool] = macro SourceInfoTransform.noArg
- /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */
- 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 +324,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
@@ -390,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 =
@@ -410,7 +418,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 +429,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 +536,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 +559,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 +622,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)
@@ -617,6 +643,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
@@ -639,7 +710,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))
@@ -697,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 =
@@ -716,7 +790,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 +801,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 +835,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 +956,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 +1018,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
@@ -954,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]
@@ -996,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]
@@ -1036,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 = {
@@ -1124,7 +1206,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))
@@ -1194,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 {
@@ -1220,7 +1304,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,12 +1315,14 @@ 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
+ 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 =
@@ -1609,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 =
@@ -1663,13 +1751,21 @@ package experimental {
}
}
- final def unary_-(): Interval = macro SourceInfoTransform.noArg
- final def unary_-%(): Interval = macro SourceInfoTransform.noArg
+ final def unary_- : Interval = macro SourceInfoTransform.noArg
- def unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ @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
+
+ /** @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
}
@@ -1779,7 +1875,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/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/Clock.scala b/core/src/main/scala/chisel3/Clock.scala
index edb07908..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]
@@ -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..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 {
@@ -435,27 +480,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
@@ -477,7 +539,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 {
@@ -645,18 +707,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 +751,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 +767,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 +790,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..7ba24585 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
@@ -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.
@@ -182,23 +192,33 @@ 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
- def isACloneOf(a: Any): Boolean = this == a || _proto == a
+ private[chisel3] def getProto: T
+
+ /** 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.getProto
+ case o => o
+ }
+ 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
@@ -211,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
@@ -235,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))
}
}
@@ -249,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
@@ -260,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
@@ -271,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
@@ -328,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.
@@ -346,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/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/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..e977d918 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -5,7 +5,8 @@ package chisel3
import scala.collection.mutable.{ArrayBuffer, HashMap}
import scala.util.Try
import scala.language.experimental.macros
-import chisel3.experimental.{BaseModule, BaseSim}
+import scala.annotation.nowarn
+import chisel3.experimental.BaseModule
import chisel3.internal._
import chisel3.internal.BaseModule.{ModuleClone, InstanceClone}
import chisel3.internal.Builder._
@@ -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,16 +37,16 @@ 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
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,""" +
@@ -81,7 +83,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 {
@@ -195,7 +201,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/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..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]
@@ -246,7 +247,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 +266,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 +292,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/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/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/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/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)}
+}
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/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
index 0cc3d131..c7b51072 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 underlying 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] 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]]
*
@@ -43,20 +39,20 @@ 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 =>
- 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(underlying)
+
+
}
/** Factory methods for constructing [[Definition]]s */
@@ -90,11 +86,12 @@ 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
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
new file mode 100644
index 00000000..503e437b
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental.hierarchy
+
+import chisel3._
+import scala.collection.mutable.{HashMap, HashSet}
+import scala.reflect.runtime.universe.TypeTag
+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 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 */
+ 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)
+ }
+
+
+ // 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(modifyReplString(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 hierarchy.
+ *
+ * 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
+
+ /** @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.
+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..97b62c23 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
@@ -14,38 +14,29 @@ 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
*/
-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] 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
}
- /** 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]]
*
@@ -65,7 +56,8 @@ case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, Is
}
/** Returns the definition of this Instance */
- def toDefinition: Definition[A] = new Definition(Left(proto))
+ override def toDefinition: Definition[A] = new Definition(Proto(proto))
+ override def toInstance: Instance[A] = this
}
@@ -75,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
}
}
@@ -105,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 b9617723..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]] = {
- val newChild = Module.do_apply(new internal.BaseModule.InstanceClone(x, name))
+ 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.isACloneOf(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_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_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/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
index 8018159f..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.
@@ -167,8 +168,149 @@ package object experimental {
// 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))
+ // ****************************** 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)
+ )
}
}
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/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 441abc92..71894887 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}
@@ -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,17 +149,28 @@ 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
}
+ // 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
* @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
@@ -203,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))
}
@@ -223,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
@@ -332,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
@@ -349,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]]
@@ -485,7 +491,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
@@ -550,6 +556,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
@@ -572,7 +580,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 = {
@@ -590,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.")
)
@@ -615,52 +613,18 @@ 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
}
- // 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
* (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)
@@ -727,14 +691,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.")
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)
}
}
diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
index f56c3b15..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 {
@@ -142,8 +143,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..68f5f18e 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
case class PrimOp(name: String) {
@@ -64,7 +65,7 @@ object PrimOp {
val AsAsyncResetOp = PrimOp("asAsyncReset")
}
-abstract class Arg {
+sealed abstract class Arg {
def localName: String = name
def contextualName(ctx: Component): String = name
def fullName(ctx: Component): String = contextualName(ctx)
@@ -86,6 +87,19 @@ case class Node(id: HasId) extends 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}]"
+ 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,6 +210,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 {
def name: String = s"[$value]"
override def contextualName(ctx: Component): String = s"${imm.contextualName(ctx)}[${value.contextualName(ctx)}]"
@@ -775,6 +790,7 @@ case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg,
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
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
@@ -784,7 +800,9 @@ 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
+// 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)
case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition
object Formal extends Enumeration {
@@ -792,14 +810,17 @@ 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
+@nowarn("msg=class Port") // delete when Port becomes private
abstract class Component extends Arg {
def id: BaseModule
def name: String
def ports: Seq[Port]
}
+@nowarn("msg=class Port") // delete when Port becomes private
case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component
+@nowarn("msg=class Port") // delete when Port becomes private
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) {
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,
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..faca3ae4 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
@@ -206,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)