summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3
diff options
context:
space:
mode:
authorJack Koenig2021-02-11 18:12:48 -0800
committerJack Koenig2021-03-12 16:16:45 -0800
commit1494231212425fd09f915d819102ca5cdef0dfcf (patch)
tree2828c723f881775bff0978592e07d3d52d78d4a9 /core/src/main/scala/chisel3
parente80e9a3ba775efd2121b17a39b6d712e1cf8fac2 (diff)
[plugin] Implement autoclonetype in the compiler plugin
Diffstat (limited to 'core/src/main/scala/chisel3')
-rw-r--r--core/src/main/scala/chisel3/Aggregate.scala56
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala8
2 files changed, 50 insertions, 14 deletions
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala
index 6942313e..30276230 100644
--- a/core/src/main/scala/chisel3/Aggregate.scala
+++ b/core/src/main/scala/chisel3/Aggregate.scala
@@ -798,6 +798,13 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
case _ => None
}
+ /** Indicates if a concrete Bundle class was compiled using the compiler plugin
+ *
+ * Used for optimizing Chisel's performance and testing Chisel itself
+ * @note This should not be used in user code!
+ */
+ 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
@@ -808,7 +815,33 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
private val _containingModule: Option[BaseModule] = Builder.currentModule
private val _containingBundles: Seq[Bundle] = Builder.updateBundleStack(this)
- override def cloneType : this.type = {
+ private def checkClone(clone: Bundle): Unit = {
+ for ((name, field) <- elements) {
+ if (clone.elements(name) eq field) {
+ throw new AutoClonetypeException(
+ s"Automatically cloned $clone has field '$name' aliased with base $this." +
+ " In the future, this will be solved automatically by the compiler plugin." +
+ " For now, ensure Chisel types used in the Bundle definition are passed through constructor arguments," +
+ " or wrapped in Input(...), Output(...), or Flipped(...) if appropriate." +
+ " As a last resort, you can override cloneType manually."
+ )
+ }
+ }
+
+ }
+
+ override def cloneType: this.type = {
+ val clone = _cloneTypeImpl.asInstanceOf[this.type]
+ checkClone(clone)
+ clone
+ }
+
+ /** 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)
+ */
+ 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
@@ -816,24 +849,19 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
val clazz = this.getClass
- def autoClonetypeError(desc: String): Nothing = {
- throw new AutoClonetypeException(s"Unable to automatically infer cloneType on $clazz: $desc")
- }
+ 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)
}
-
- for ((name, field) <- elements) {
- if (clone.elements(name) eq field) {
- autoClonetypeError(s"Automatically cloned $clone has field $name aliased with base $this." +
- " In the future, this can be solved by wrapping the field in Field(...)," +
- " see https://github.com/freechipsproject/chisel3/pull/909." +
- " For now, ensure Chisel types used in the Bundle definition are passed through constructor arguments," +
- " or wrapped in Input(...), Output(...), or Flipped(...) if appropriate.")
- }
- }
+ checkClone(clone)
}
val mirror = runtimeMirror(clazz.getClassLoader)
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index e95384cd..b1016a2e 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -311,6 +311,8 @@ 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]]
@@ -530,6 +532,12 @@ private[chisel3] object Builder extends LazyLogging {
dynamicContext.currentReset = newReset
}
+ // This should only be used for testing
+ def allowReflectiveAutoCloneType: Boolean = dynamicContext.allowReflectiveAutoCloneType
+ def allowReflectiveAutoCloneType_=(value: Boolean): Unit = {
+ dynamicContext.allowReflectiveAutoCloneType = value
+ }
+
def forcedClock: Clock = currentClock.getOrElse(
throwException("Error: No implicit clock.")
)