summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/internal
diff options
context:
space:
mode:
authorJack Koenig2021-09-17 21:01:26 -0700
committerJack Koenig2021-09-17 21:01:26 -0700
commit5c8c19345e6711279594cf1f9ddab33623c8eba7 (patch)
treed9d6ced3934aa4a8be3dec19ddcefe50a7a93d5a /core/src/main/scala/chisel3/internal
parente63b9667d89768e0ec6dc8a9153335cb48a213a7 (diff)
parent958904cb2f2f65d02b2ab3ec6d9ec2e06d04e482 (diff)
Merge branch 'master' into 3.5-release
Diffstat (limited to 'core/src/main/scala/chisel3/internal')
-rw-r--r--core/src/main/scala/chisel3/internal/BiConnect.scala43
-rw-r--r--core/src/main/scala/chisel3/internal/Binding.scala22
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala133
-rw-r--r--core/src/main/scala/chisel3/internal/Error.scala113
-rw-r--r--core/src/main/scala/chisel3/internal/MonoConnect.scala8
-rw-r--r--core/src/main/scala/chisel3/internal/Namer.scala14
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/Converter.scala109
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala83
8 files changed, 414 insertions, 111 deletions
diff --git a/core/src/main/scala/chisel3/internal/BiConnect.scala b/core/src/main/scala/chisel3/internal/BiConnect.scala
index 1ee149ee..aa58cb95 100644
--- a/core/src/main/scala/chisel3/internal/BiConnect.scala
+++ b/core/src/main/scala/chisel3/internal/BiConnect.scala
@@ -3,12 +3,16 @@
package chisel3.internal
import chisel3._
+import chisel3.experimental.dataview.reify
import chisel3.experimental.{Analog, BaseModule, attach}
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl.{Connect, DefInvalid}
+
import scala.language.experimental.macros
import chisel3.internal.sourceinfo._
+import scala.annotation.tailrec
+
/**
* BiConnect.connect executes a bidirectional connection element-wise.
*
@@ -113,14 +117,33 @@ private[chisel3] object BiConnect {
}
}
}
- // Handle Records defined in Chisel._ code (change to NotStrict)
- case (left_r: Record, right_r: Record) => (left_r.compileOptions, right_r.compileOptions) match {
- case (ExplicitCompileOptions.NotStrict, _) =>
- left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
- case (_, ExplicitCompileOptions.NotStrict) =>
- left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
- case _ => recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)
- }
+ // Handle Records defined in Chisel._ code by emitting a FIRRTL partial connect
+ case pair @ (left_r: Record, right_r: Record) =>
+ val notStrict =
+ Seq(left_r.compileOptions, right_r.compileOptions).contains(ExplicitCompileOptions.NotStrict)
+ if (notStrict) {
+ // Traces flow from a child Data to its parent
+ @tailrec def traceFlow(currentlyFlipped: Boolean, data: Data): Boolean = {
+ import SpecifiedDirection.{Input => SInput, Flip => SFlip}
+ val sdir = data.specifiedDirection
+ val flipped = sdir == SInput || sdir == SFlip
+ data.binding.get match {
+ case ChildBinding(parent) => traceFlow(flipped ^ currentlyFlipped, parent)
+ case PortBinding(enclosure) =>
+ val childPort = enclosure != context_mod
+ childPort ^ flipped ^ currentlyFlipped
+ case _ => true
+ }
+ }
+ def canBeSink(data: Data): Boolean = traceFlow(true, data)
+ def canBeSource(data: Data): Boolean = traceFlow(false, data)
+ // chisel3 <> is commutative but FIRRTL <- is not
+ val flipConnection = !canBeSink(left_r) || !canBeSource(right_r)
+ val (newLeft, newRight) = if (flipConnection) pair.swap else pair
+ newLeft.bulkConnect(newRight)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ } else {
+ recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)
+ }
// Handle Records connected to DontCare (change to NotStrict)
case (left_r: Record, DontCare) =>
@@ -215,8 +238,10 @@ private[chisel3] object BiConnect {
// This function checks if element-level connection operation allowed.
// Then it either issues it or throws the appropriate exception.
- def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Element, right: Element, context_mod: RawModule): Unit = {
+ def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, _left: Element, _right: Element, context_mod: RawModule): Unit = {
import BindingDirection.{Internal, Input, Output} // Using extensively so import these
+ val left = reify(_left)
+ val right = reify(_right)
// If left or right have no location, assume in context module
// This can occur if one of them is a literal, unbound will error previously
val left_mod: BaseModule = left.topBinding.location.getOrElse(context_mod)
diff --git a/core/src/main/scala/chisel3/internal/Binding.scala b/core/src/main/scala/chisel3/internal/Binding.scala
index 4442c62e..a0dcc20c 100644
--- a/core/src/main/scala/chisel3/internal/Binding.scala
+++ b/core/src/main/scala/chisel3/internal/Binding.scala
@@ -6,6 +6,8 @@ import chisel3._
import chisel3.experimental.BaseModule
import chisel3.internal.firrtl.LitArg
+import scala.collection.immutable.VectorMap
+
/** Requires that a node is hardware ("bound")
*/
object requireIsHardware {
@@ -110,12 +112,32 @@ case class ChildBinding(parent: Data) extends Binding {
case class SampleElementBinding[T <: Data](parent: Vec[T]) extends Binding {
def location = parent.topBinding.location
}
+/** Special binding for Mem types */
+case class MemTypeBinding[T <: Data](parent: MemBase[T]) extends Binding {
+ def location: Option[BaseModule] = parent._parent
+}
// A DontCare element has a specific Binding, somewhat like a literal.
// It is a source (RHS). It may only be connected/applied to sinks.
case class DontCareBinding() extends UnconstrainedBinding
+// Views currently only support 1:1 Element-level mappings
+private[chisel3] case class ViewBinding(target: Element) extends UnconstrainedBinding
+/** Binding for Aggregate Views
+ * @param childMap Mapping from children of this view to each child's target
+ * @param target Optional Data this Aggregate views if the view is total and the target is a Data
+ */
+private[chisel3] case class AggregateViewBinding(childMap: Map[Data, Element], target: Option[Data]) extends UnconstrainedBinding
+
+
+/** Binding for Data's returned from accessing an Instance/Definition members, if not readable/writable port */
+private[chisel3] case object CrossModuleBinding extends TopBinding {
+ def location = None
+}
+
sealed trait LitBinding extends UnconstrainedBinding with ReadOnlyBinding
// Literal binding attached to a element that is not part of a Bundle.
case class ElementLitBinding(litArg: LitArg) extends LitBinding
// Literal binding attached to the root of a Bundle, containing literal values of its children.
case class BundleLitBinding(litMap: Map[Data, LitArg]) extends LitBinding
+// Literal binding attached to the root of a Vec, containing literal values of its children.
+case class VecLitBinding(litMap: VectorMap[Data, LitArg]) extends LitBinding
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index b7772aea..441abc92 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -6,10 +6,13 @@ import scala.util.DynamicVariable
import scala.collection.mutable.ArrayBuffer
import chisel3._
import chisel3.experimental._
+import chisel3.experimental.hierarchy.Instance
import chisel3.internal.firrtl._
import chisel3.internal.naming._
import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
-import _root_.firrtl.annotations.AnnotationUtils.{validComponentName}
+import _root_.firrtl.annotations.AnnotationUtils.validComponentName
+import _root_.firrtl.{AnnotationSeq, RenameMap}
+import chisel3.experimental.dataview.{reify, reifySingleData}
import chisel3.internal.Builder.Prefix
import logger.LazyLogging
@@ -17,6 +20,7 @@ import scala.collection.mutable
private[chisel3] class Namespace(keywords: Set[String]) {
private val names = collection.mutable.HashMap[String, Long]()
+ def copyTo(other: Namespace): Unit = names.foreach { case (s: String, l: Long) => other.names(s) = l }
for (keyword <- keywords)
names(keyword) = 1
@@ -83,8 +87,10 @@ trait InstanceId {
private[chisel3] trait HasId extends InstanceId {
private[chisel3] def _onModuleClose: Unit = {}
- private[chisel3] val _parent: Option[BaseModule] = Builder.currentModule
- _parent.foreach(_.addId(this))
+ private[chisel3] var _parent: Option[BaseModule] = Builder.currentModule
+
+ // Set if the returned top-level module of a nested call to the Chisel Builder, see Definition.apply
+ private[chisel3] var _circuit: Option[BaseModule] = None
private[chisel3] val _id: Long = Builder.idGen.next
@@ -215,32 +221,53 @@ private[chisel3] trait HasId extends InstanceId {
private[chisel3] def getRef: Arg = _ref.get
private[chisel3] def getOptionRef: Option[Arg] = _ref
+ private def refName(c: Component): String = _ref match {
+ case Some(arg) => arg fullName c
+ case None => computeName(None, None).get
+ }
+
+ // Helper for reifying views if they map to a single Target
+ private[chisel3] def reifyTarget: Option[Data] = this match {
+ case d: Data => reifySingleData(d) // Only Data can be views
+ case bad => throwException(s"This shouldn't be possible - got $bad with ${_parent}")
+ }
+
+ // Helper for reifying the parent of a view if the view maps to a single Target
+ private[chisel3] def reifyParent: BaseModule = reifyTarget.flatMap(_._parent).getOrElse(ViewParent)
+
// Implementation of public methods.
def instanceName: String = _parent match {
- case Some(p) => p._component match {
- case Some(c) => _ref match {
- case Some(arg) => arg fullName c
- case None => computeName(None, None).get
+ case Some(ViewParent) => reifyTarget.map(_.instanceName).getOrElse(this.refName(ViewParent.fakeComponent))
+ case Some(p) =>
+ (p._component, this) match {
+ case (Some(c), _) => refName(c)
+ case (None, d: Data) if d.topBindingOpt == Some(CrossModuleBinding) => _ref.get.localName
+ case (None, _) => throwException(s"signalName/pathName should be called after circuit elaboration: $this, ${_parent}")
}
- case None => throwException("signalName/pathName should be called after circuit elaboration")
- }
case None => throwException("this cannot happen")
}
def pathName: String = _parent match {
case None => instanceName
+ case Some(ViewParent) => s"${reifyParent.pathName}.$instanceName"
case Some(p) => s"${p.pathName}.$instanceName"
}
def parentPathName: String = _parent match {
+ case Some(ViewParent) => reifyParent.pathName
case Some(p) => p.pathName
case None => throwException(s"$instanceName doesn't have a parent")
}
def parentModName: String = _parent match {
+ case Some(ViewParent) => reifyParent.name
case Some(p) => p.name
case None => throwException(s"$instanceName doesn't have a parent")
}
// TODO Should this be public?
protected def circuitName: String = _parent match {
- case None => instanceName
+ case None => _circuit match {
+ case None => instanceName
+ case Some(o) => o.circuitName
+ }
+ case Some(ViewParent) => reifyParent.circuitName
case Some(p) => p.circuitName
}
@@ -279,8 +306,12 @@ private[chisel3] trait NamedComponent extends HasId {
val name = this.instanceName
if (!validComponentName(name)) throwException(s"Illegal component name: $name (note: literals are illegal)")
import _root_.firrtl.annotations.{Target, TargetToken}
+ val root = _parent.map {
+ case ViewParent => reifyParent
+ case other => other
+ }.get.getTarget // All NamedComponents will have a parent, only the top module can have None here
Target.toTargetTokens(name).toList match {
- case TargetToken.Ref(r) :: components => ReferenceTarget(this.circuitName, this.parentModName, Nil, r, components)
+ case TargetToken.Ref(r) :: components => root.ref(r).copy(component = components)
case other =>
throw _root_.firrtl.annotations.Target.NamedException(s"Cannot convert $name into [[ReferenceTarget]]: $other")
}
@@ -288,8 +319,10 @@ private[chisel3] trait NamedComponent extends HasId {
final def toAbsoluteTarget: ReferenceTarget = {
val localTarget = toTarget
+ def makeTarget(p: BaseModule) = p.toAbsoluteTarget.ref(localTarget.ref).copy(component = localTarget.component)
_parent match {
- case Some(parent) => parent.toAbsoluteTarget.ref(localTarget.ref).copy(component = localTarget.component)
+ case Some(ViewParent) => makeTarget(reifyParent)
+ case Some(parent) => makeTarget(parent)
case None => localTarget
}
}
@@ -304,19 +337,29 @@ private[chisel3] class ChiselContext() {
// Records the different prefixes which have been scoped at this point in time
var prefixStack: Prefix = Nil
+
+ // Views belong to a separate namespace (for renaming)
+ // The namespace outside of Builder context is useless, but it ensures that views can still be created
+ // and the resulting .toTarget is very clearly useless (_$$View$$_...)
+ val viewNamespace = Namespace.empty
}
-private[chisel3] class DynamicContext() {
+private[chisel3] class DynamicContext(val annotationSeq: AnnotationSeq) {
val globalNamespace = Namespace.empty
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]]
*/
val aspectModule: mutable.HashMap[BaseModule, BaseModule] = mutable.HashMap.empty[BaseModule, BaseModule]
+ // Views that do not correspond to a single ReferenceTarget and thus require renaming
+ val unnamedViews: ArrayBuffer[Data] = ArrayBuffer.empty
+
// Set by object Module.apply before calling class Module constructor
// Used to distinguish between no Module() wrapping, multiple wrappings, and rewrapping
var readyForModuleConstr: Boolean = false
@@ -325,6 +368,8 @@ private[chisel3] class DynamicContext() {
var currentReset: Option[Reset] = None
val errors = new ErrorLog
val namingStack = new NamingStack
+ // Used to indicate if this is the top-level module of full elaboration, or from a Definition
+ var inDefinition: Boolean = false
}
private[chisel3] object Builder extends LazyLogging {
@@ -339,6 +384,11 @@ private[chisel3] object Builder extends LazyLogging {
dynamicContextVar.value.get
}
+ // Returns the current dynamic context
+ def captureContext(): DynamicContext = dynamicContext
+ // Sets the current dynamic contents
+ def restoreContext(dc: DynamicContext) = dynamicContextVar.value = Some(dc)
+
// Ensure we have a thread-specific ChiselContext
private val chiselContext = new ThreadLocal[ChiselContext]{
override def initialValue: ChiselContext = {
@@ -365,8 +415,12 @@ private[chisel3] object Builder extends LazyLogging {
def globalNamespace: Namespace = dynamicContext.globalNamespace
def components: ArrayBuffer[Component] = dynamicContext.components
def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations
+ def annotationSeq: AnnotationSeq = dynamicContext.annotationSeq
def namingStack: NamingStack = dynamicContext.namingStack
+ def unnamedViews: ArrayBuffer[Data] = dynamicContext.unnamedViews
+ def viewNamespace: Namespace = chiselContext.get.viewNamespace
+
// Puts a prefix string onto the prefix stack
def pushPrefix(d: String): Unit = {
val context = chiselContext.get()
@@ -400,6 +454,7 @@ private[chisel3] object Builder extends LazyLogging {
case PortBinding(mod) if Builder.currentModule.contains(mod) => data.seedOpt
case PortBinding(mod) => map2(mod.seedOpt, data.seedOpt)(_ + "_" + _)
case (_: LitBinding | _: DontCareBinding) => None
+ case _ => Some("view_") // TODO implement
}
id match {
case d: Data => recData(d)
@@ -529,6 +584,22 @@ private[chisel3] object Builder extends LazyLogging {
dynamicContext.currentReset = newReset
}
+ def inDefinition: Boolean = {
+ dynamicContextVar.value
+ .map(_.inDefinition)
+ .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.")
)
@@ -588,6 +659,10 @@ private[chisel3] object Builder extends LazyLogging {
* (Note: Map is Iterable[Tuple2[_,_]] and thus excluded)
*/
def nameRecursively(prefix: String, nameMe: Any, namer: (HasId, String) => Unit): Unit = nameMe match {
+ case (id: Instance[_]) => id.cloned match {
+ case Right(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix)
+ case _ =>
+ }
case (id: HasId) => namer(id, prefix)
case Some(elt) => nameRecursively(prefix, elt, namer)
case (iter: Iterable[_]) if iter.hasDefiniteSize =>
@@ -633,21 +708,37 @@ private[chisel3] object Builder extends LazyLogging {
}
}
-
- def build[T <: RawModule](f: => T): (Circuit, T) = {
- build(f, new DynamicContext())
+ // Builds a RenameMap for all Views that do not correspond to a single Data
+ // These Data give a fake ReferenceTarget for .toTarget and .toReferenceTarget that the returned
+ // RenameMap can split into the constituent parts
+ private[chisel3] def makeViewRenameMap: RenameMap = {
+ val renames = RenameMap()
+ for (view <- unnamedViews) {
+ val localTarget = view.toTarget
+ val absTarget = view.toAbsoluteTarget
+ val elts = getRecursiveFields.lazily(view, "")
+ .collect { case (elt: Element, _) => elt }
+ for (elt <- elts) {
+ val targetOfView = reify(elt)
+ renames.record(localTarget, targetOfView.toTarget)
+ renames.record(absTarget, targetOfView.toAbsoluteTarget)
+ }
+ }
+ renames
}
- private [chisel3] def build[T <: RawModule](f: => T, dynamicContext: DynamicContext): (Circuit, T) = {
+ private [chisel3] def build[T <: BaseModule](f: => T, dynamicContext: DynamicContext): (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.warn("Elaborating design...")
+ logger.info("Elaborating design...")
val mod = f
mod.forceName(None, mod.name, globalNamespace)
- errors.checkpoint()
- logger.warn("Done elaborating.")
+ errors.checkpoint(logger)
+ logger.info("Done elaborating.")
- (Circuit(components.last.name, components, annotations), mod)
+ (Circuit(components.last.name, components.toSeq, annotations.toSeq, makeViewRenameMap), mod)
}
}
initializeSingletons()
diff --git a/core/src/main/scala/chisel3/internal/Error.scala b/core/src/main/scala/chisel3/internal/Error.scala
index 6a1794ce..d6e0c0e6 100644
--- a/core/src/main/scala/chisel3/internal/Error.scala
+++ b/core/src/main/scala/chisel3/internal/Error.scala
@@ -4,13 +4,84 @@ package chisel3.internal
import scala.annotation.tailrec
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
+import _root_.logger.Logger
-class ChiselException(message: String, cause: Throwable = null) extends Exception(message, cause) {
+object ExceptionHelpers {
+
+ /** Root packages that are not typically relevant to Chisel user code. */
+ final val packageTrimlist: Set[String] = Set("chisel3", "scala", "java", "jdk", "sun", "sbt")
+
+ /** The object name of Chisel's internal `Builder`. */
+ final val builderName: String = chisel3.internal.Builder.getClass.getName
+
+ /** Return a stack trace element that looks like `... (someMessage)`.
+ * @param message an optional message to include
+ */
+ def ellipsis(message: Option[String] = None): StackTraceElement =
+ new StackTraceElement("..", " ", message.getOrElse(""), -1)
+
+ /** Utility methods that can be added to exceptions.
+ */
+ implicit class ThrowableHelpers(throwable: Throwable) {
+
+ /** For an exception, mutably trim a stack trace to user code only.
+ *
+ * This does the following actions to the stack trace:
+ *
+ * 1. From the top, remove elements while the (root) package matches the packageTrimlist
+ * 2. Optionally, from the bottom, remove elements until the class matches an anchor
+ * 3. From the anchor (or the bottom), remove elements while the (root) package matches the packageTrimlist
+ *
+ * @param packageTrimlist packages that should be removed from the stack trace
+ * @param anchor an optional class name at which user execution might begin, e.g., a main object
+ * @return nothing as this mutates the exception directly
+ */
+ def trimStackTraceToUserCode(
+ packageTrimlist: Set[String] = packageTrimlist,
+ anchor: Option[String] = Some(builderName)
+ ): Unit = {
+ def inTrimlist(ste: StackTraceElement) = {
+ val packageName = ste.getClassName().takeWhile(_ != '.')
+ packageTrimlist.contains(packageName)
+ }
+
+ // Step 1: Remove elements from the top in the package trimlist
+ ((a: Array[StackTraceElement]) => a.dropWhile(inTrimlist))
+ // Step 2: Optionally remove elements from the bottom until the anchor
+ .andThen(_.reverse)
+ .andThen( a =>
+ anchor match {
+ case Some(b) => a.dropWhile(ste => !ste.getClassName.startsWith(b))
+ case None => a
+ }
+ )
+ // Step 3: Remove elements from the bottom in the package trimlist
+ .andThen(_.dropWhile(inTrimlist))
+ // Step 4: Reverse back to the original order
+ .andThen(_.reverse.toArray)
+ // Step 5: Add ellipsis stack trace elements and "--full-stacktrace" info
+ .andThen(a =>
+ ellipsis() +:
+ a :+
+ ellipsis() :+
+ ellipsis(Some("Stack trace trimmed to user code only. Rerun with --full-stacktrace to see the full stack trace")))
+ // Step 5: Mutate the stack trace in this exception
+ .andThen(throwable.setStackTrace(_))
+ .apply(throwable.getStackTrace)
+ }
+
+ }
+
+}
+
+class ChiselException(message: String, cause: Throwable = null) extends Exception(message, cause, true, true) {
/** Package names whose stack trace elements should be trimmed when generating a trimmed stack trace */
+ @deprecated("Use ExceptionHelpers.packageTrimlist. This will be removed in Chisel 3.6", "3.5")
val blacklistPackages: Set[String] = Set("chisel3", "scala", "java", "sun", "sbt")
/** The object name of Chisel's internal `Builder`. Everything stack trace element after this will be trimmed. */
+ @deprecated("Use ExceptionHelpers.builderName. This will be removed in Chisel 3.6", "3.5")
val builderName: String = chisel3.internal.Builder.getClass.getName
/** Examine a [[Throwable]], to extract all its causes. Innermost cause is first.
@@ -27,7 +98,7 @@ class ChiselException(message: String, cause: Throwable = null) extends Exceptio
/** Returns true if an exception contains */
private def containsBuilder(throwable: Throwable): Boolean =
throwable.getStackTrace().collectFirst {
- case ste if ste.getClassName().startsWith(builderName) => throwable
+ case ste if ste.getClassName().startsWith(ExceptionHelpers.builderName) => throwable
}.isDefined
/** Examine this [[ChiselException]] and it's causes for the first [[Throwable]] that contains a stack trace including
@@ -55,19 +126,12 @@ class ChiselException(message: String, cause: Throwable = null) extends Exceptio
}
val trimmedLeft = throwable.getStackTrace().view.dropWhile(isBlacklisted)
- val trimmedReverse = trimmedLeft.reverse
+ val trimmedReverse = trimmedLeft.toIndexedSeq.reverse.view
.dropWhile(ste => !ste.getClassName.startsWith(builderName))
.dropWhile(isBlacklisted)
- trimmedReverse.reverse.toArray
+ trimmedReverse.toIndexedSeq.reverse.toArray
}
- /** trims the top of the stack of elements belonging to [[blacklistPackages]]
- * then trims the bottom elements until it reaches [[builderName]]
- * then continues trimming elements belonging to [[blacklistPackages]]
- */
- @deprecated("This method will be removed in 3.4", "3.3")
- def trimmedStackTrace: Array[StackTraceElement] = trimmedStackTrace(this)
-
def chiselStackTrace: String = {
val trimmed = trimmedStackTrace(likelyCause)
@@ -121,35 +185,36 @@ private[chisel3] class ErrorLog {
}
/** Throw an exception if any errors have yet occurred. */
- def checkpoint(): Unit = {
+ def checkpoint(logger: Logger): Unit = {
deprecations.foreach { case ((message, sourceLoc), count) =>
- println(s"${ErrorLog.depTag} $sourceLoc ($count calls): $message")
+ logger.warn(s"${ErrorLog.depTag} $sourceLoc ($count calls): $message")
}
- errors foreach println
+ errors.foreach(e => logger.error(e.toString))
if (!deprecations.isEmpty) {
- println(s"${ErrorLog.warnTag} ${Console.YELLOW}There were ${deprecations.size} deprecated function(s) used." +
+ logger.warn(s"${ErrorLog.warnTag} ${Console.YELLOW}There were ${deprecations.size} deprecated function(s) used." +
s" These may stop compiling in a future release - you are encouraged to fix these issues.${Console.RESET}")
- println(s"${ErrorLog.warnTag} Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods:")
- println(s"${ErrorLog.warnTag} In the sbt interactive console, enter:")
- println(s"""${ErrorLog.warnTag} set scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation")""")
- println(s"${ErrorLog.warnTag} or, in your build.sbt, add the line:")
- println(s"""${ErrorLog.warnTag} scalacOptions := Seq("-unchecked", "-deprecation")""")
+ logger.warn(s"${ErrorLog.warnTag} Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods:")
+ logger.warn(s"${ErrorLog.warnTag} In the sbt interactive console, enter:")
+ logger.warn(s"""${ErrorLog.warnTag} set scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation")""")
+ logger.warn(s"${ErrorLog.warnTag} or, in your build.sbt, add the line:")
+ logger.warn(s"""${ErrorLog.warnTag} scalacOptions := Seq("-unchecked", "-deprecation")""")
}
val allErrors = errors.filter(_.isFatal)
val allWarnings = errors.filter(!_.isFatal)
if (!allWarnings.isEmpty && !allErrors.isEmpty) {
- println(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} and ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ logger.warn(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} and ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
} else if (!allWarnings.isEmpty) {
- println(s"${ErrorLog.warnTag} There were ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ logger.warn(s"${ErrorLog.warnTag} There were ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
} else if (!allErrors.isEmpty) {
- println(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} during hardware elaboration.")
+ logger.warn(s"${ErrorLog.errTag} There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} during hardware elaboration.")
}
if (!allErrors.isEmpty) {
- throwException("Fatal errors during hardware elaboration")
+ throw new ChiselException("Fatal errors during hardware elaboration. Look above for error list.")
+ with scala.util.control.NoStackTrace
} else {
// No fatal errors, clear accumulated warnings since they've been reported
errors.clear()
diff --git a/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala
index 2155894a..5cbab329 100644
--- a/core/src/main/scala/chisel3/internal/MonoConnect.scala
+++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala
@@ -5,7 +5,9 @@ package chisel3.internal
import chisel3._
import chisel3.experimental.{Analog, BaseModule, EnumType, FixedPoint, Interval, UnsafeEnum}
import chisel3.internal.Builder.pushCommand
+import chisel3.experimental.dataview.reify
import chisel3.internal.firrtl.{Connect, DefInvalid}
+
import scala.language.experimental.macros
import chisel3.internal.sourceinfo.SourceInfo
@@ -103,6 +105,8 @@ private[chisel3] object MonoConnect {
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: ResetType, source_e: Reset) =>
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
+ case (sink_e: Reset, source_e: ResetType) =>
+ elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: EnumType, source_e: UnsafeEnum) =>
elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
case (sink_e: EnumType, source_e: EnumType) if sink_e.typeEquivalent(source_e) =>
@@ -186,8 +190,10 @@ private[chisel3] object MonoConnect {
// This function checks if element-level connection operation allowed.
// Then it either issues it or throws the appropriate exception.
- def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Element, source: Element, context_mod: RawModule): Unit = {
+ def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, _sink: Element, _source: Element, context_mod: RawModule): Unit = {
import BindingDirection.{Internal, Input, Output} // Using extensively so import these
+ val sink = reify(_sink)
+ 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)
diff --git a/core/src/main/scala/chisel3/internal/Namer.scala b/core/src/main/scala/chisel3/internal/Namer.scala
index 1694d71d..c6e36cb6 100644
--- a/core/src/main/scala/chisel3/internal/Namer.scala
+++ b/core/src/main/scala/chisel3/internal/Namer.scala
@@ -8,9 +8,8 @@ import chisel3.experimental.NoChiselNamePrefix
import scala.collection.mutable.Stack
import scala.collection.mutable.ListBuffer
-import scala.collection.JavaConversions._
-
import java.util.IdentityHashMap
+import scala.collection.JavaConverters._
/** Recursive Function Namer overview
*
@@ -81,7 +80,14 @@ class NamingContext extends NamingContextInterface {
def addDescendant(ref: Any, descendant: NamingContext) {
ref match {
case ref: AnyRef =>
- descendants.getOrElseUpdate(ref, ListBuffer[NamingContext]()) += descendant
+ // getOrElseUpdate
+ val l = descendants.get(ref)
+ val buf = if (l != null) l else {
+ val value = ListBuffer[NamingContext]()
+ descendants.put(ref, value)
+ value
+ }
+ buf += descendant
case _ => anonymousDescendants += descendant
}
}
@@ -111,7 +117,7 @@ class NamingContext extends NamingContextInterface {
}
}
- for (descendant <- descendants.values().flatten) {
+ for (descendant <- descendants.values.asScala.flatten) {
// Where we have a broken naming link, just ignore the missing parts
descendant.namePrefix(prefix)
}
diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
index aefbf8ab..f56c3b15 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
@@ -3,12 +3,13 @@
package chisel3.internal.firrtl
import chisel3._
import chisel3.experimental._
-import chisel3.internal.sourceinfo.{NoSourceInfo, SourceLine, SourceInfo}
+import chisel3.internal.sourceinfo.{NoSourceInfo, SourceInfo, SourceLine, UnlocatableSourceInfo}
import firrtl.{ir => fir}
-import chisel3.internal.{castToInt, throwException}
+import chisel3.internal.{HasId, castToInt, throwException}
import scala.annotation.tailrec
import scala.collection.immutable.Queue
+import scala.collection.immutable.LazyList // Needed for 2.12 alias
private[chisel3] object Converter {
// TODO modeled on unpack method on Printable, refactor?
@@ -24,6 +25,24 @@ private[chisel3] object Converter {
case Percent => ("%%", List.empty)
}
+ private def reportInternalError(msg: String): Nothing = {
+ val link = "https://github.com/chipsalliance/chisel3/issues/new"
+ val fullMsg = s"Internal Error! $msg This is a bug in Chisel, please file an issue at '$link'"
+ throwException(fullMsg)
+ }
+
+ def getRef(id: HasId, sourceInfo: SourceInfo): Arg =
+ id.getOptionRef.getOrElse {
+ val module = id._parent.map(m => s" '$id' was defined in module '$m'.").getOrElse("")
+ val loc = sourceInfo.makeMessage(" " + _)
+ reportInternalError(s"Could not get ref for '$id'$loc!$module")
+ }
+
+ private def clonedModuleIOError(mod: BaseModule, name: String, sourceInfo: SourceInfo): Nothing = {
+ val loc = sourceInfo.makeMessage(" " + _)
+ reportInternalError(s"Trying to convert a cloned IO of $mod inside of $mod itself$loc!")
+ }
+
def convert(info: SourceInfo): fir.Info = info match {
case _: NoSourceInfo => fir.NoInfo
case SourceLine(fn, line, col) => fir.FileInfo(fir.StringLit(s"$fn $line:$col"))
@@ -41,37 +60,40 @@ private[chisel3] object Converter {
// TODO
// * Memoize?
// * Move into the Chisel IR?
- def convert(arg: Arg, ctx: Component): fir.Expression = arg match {
+ def convert(arg: Arg, ctx: Component, info: SourceInfo): fir.Expression = arg match {
case Node(id) =>
- convert(id.getRef, ctx)
+ convert(getRef(id, info), ctx, info)
case Ref(name) =>
fir.Reference(name, fir.UnknownType)
case Slot(imm, name) =>
- fir.SubField(convert(imm, ctx), name, fir.UnknownType)
+ fir.SubField(convert(imm, ctx, info), name, fir.UnknownType)
case Index(imm, ILit(idx)) =>
- fir.SubIndex(convert(imm, ctx), castToInt(idx, "Index"), fir.UnknownType)
+ fir.SubIndex(convert(imm, ctx, info), castToInt(idx, "Index"), fir.UnknownType)
case Index(imm, value) =>
- fir.SubAccess(convert(imm, ctx), convert(value, ctx), fir.UnknownType)
+ fir.SubAccess(convert(imm, ctx, info), convert(value, ctx, info), fir.UnknownType)
case ModuleIO(mod, name) =>
if (mod eq ctx.id) fir.Reference(name, fir.UnknownType)
- else fir.SubField(fir.Reference(mod.getRef.name, fir.UnknownType), name, fir.UnknownType)
+ else fir.SubField(fir.Reference(getRef(mod, info).name, fir.UnknownType), name, fir.UnknownType)
+ case ModuleCloneIO(mod, name) =>
+ if (mod eq ctx.id) clonedModuleIOError(mod, name, info)
+ else fir.Reference(name)
case u @ ULit(n, UnknownWidth()) =>
fir.UIntLiteral(n, fir.IntWidth(u.minWidth))
case ULit(n, w) =>
fir.UIntLiteral(n, convert(w))
case slit @ SLit(n, w) => fir.SIntLiteral(n, convert(w))
val unsigned = if (n < 0) (BigInt(1) << slit.width.get) + n else n
- val uint = convert(ULit(unsigned, slit.width), ctx)
+ val uint = convert(ULit(unsigned, slit.width), ctx, info)
fir.DoPrim(firrtl.PrimOps.AsSInt, Seq(uint), Seq.empty, fir.UnknownType)
// TODO Simplify
case fplit @ FPLit(n, w, bp) =>
val unsigned = if (n < 0) (BigInt(1) << fplit.width.get) + n else n
- val uint = convert(ULit(unsigned, fplit.width), ctx)
+ val uint = convert(ULit(unsigned, fplit.width), ctx, info)
val lit = bp.asInstanceOf[KnownBinaryPoint].value
fir.DoPrim(firrtl.PrimOps.AsFixedPoint, Seq(uint), Seq(lit), fir.UnknownType)
case intervalLit @ IntervalLit(n, w, bp) =>
val unsigned = if (n < 0) (BigInt(1) << intervalLit.width.get) + n else n
- val uint = convert(ULit(unsigned, intervalLit.width), ctx)
+ val uint = convert(ULit(unsigned, intervalLit.width), ctx, info)
val lit = bp.asInstanceOf[KnownBinaryPoint].value
fir.DoPrim(firrtl.PrimOps.AsInterval, Seq(uint), Seq(n, n, lit), fir.UnknownType)
case lit: ILit =>
@@ -84,7 +106,7 @@ private[chisel3] object Converter {
val consts = e.args.collect { case ILit(i) => i }
val args = e.args.flatMap {
case _: ILit => None
- case other => Some(convert(other, ctx))
+ case other => Some(convert(other, ctx, e.sourceInfo))
}
val expr = e.op.name match {
case "mux" =>
@@ -95,44 +117,45 @@ private[chisel3] object Converter {
}
Some(fir.DefNode(convert(e.sourceInfo), e.name, expr))
case e @ DefWire(info, id) =>
- Some(fir.DefWire(convert(info), e.name, extractType(id)))
+ Some(fir.DefWire(convert(info), e.name, extractType(id, info)))
case e @ DefReg(info, id, clock) =>
- Some(fir.DefRegister(convert(info), e.name, extractType(id), convert(clock, ctx),
- firrtl.Utils.zero, convert(id.getRef, ctx)))
+ Some(fir.DefRegister(convert(info), e.name, extractType(id, info), convert(clock, ctx, info),
+ firrtl.Utils.zero, convert(getRef(id, info), ctx, info)))
case e @ DefRegInit(info, id, clock, reset, init) =>
- Some(fir.DefRegister(convert(info), e.name, extractType(id), convert(clock, ctx),
- convert(reset, ctx), convert(init, ctx)))
+ Some(fir.DefRegister(convert(info), e.name, extractType(id, info), convert(clock, ctx, info),
+ convert(reset, ctx, info), convert(init, ctx, info)))
case e @ DefMemory(info, id, t, size) =>
- Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, false))
+ Some(firrtl.CDefMemory(convert(info), e.name, extractType(t, info), size, false))
case e @ DefSeqMemory(info, id, t, size, ruw) =>
- Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, true, ruw))
+ Some(firrtl.CDefMemory(convert(info), e.name, extractType(t, info), size, true, ruw))
case e: DefMemPort[_] =>
+ val info = e.sourceInfo
Some(firrtl.CDefMPort(convert(e.sourceInfo), e.name, fir.UnknownType,
- e.source.fullName(ctx), Seq(convert(e.index, ctx), convert(e.clock, ctx)), convert(e.dir)))
+ e.source.fullName(ctx), Seq(convert(e.index, ctx, info), convert(e.clock, ctx, info)), convert(e.dir)))
case Connect(info, loc, exp) =>
- Some(fir.Connect(convert(info), convert(loc, ctx), convert(exp, ctx)))
+ Some(fir.Connect(convert(info), convert(loc, ctx, info), convert(exp, ctx, info)))
case BulkConnect(info, loc, exp) =>
- Some(fir.PartialConnect(convert(info), convert(loc, ctx), convert(exp, ctx)))
+ Some(fir.PartialConnect(convert(info), convert(loc, ctx, info), convert(exp, ctx, info)))
case Attach(info, locs) =>
- Some(fir.Attach(convert(info), locs.map(l => convert(l, ctx))))
+ Some(fir.Attach(convert(info), locs.map(l => convert(l, ctx, info))))
case DefInvalid(info, arg) =>
- Some(fir.IsInvalid(convert(info), convert(arg, ctx)))
+ 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), firrtl.Utils.one))
- case Printf(info, clock, pable) =>
+ Some(fir.Stop(convert(info), ret, convert(clock, ctx, info), firrtl.Utils.one))
+ case e @ Printf(_, info, clock, pable) =>
val (fmt, args) = unpack(pable, ctx)
Some(fir.Print(convert(info), fir.StringLit(fmt),
- args.map(a => convert(a, ctx)), convert(clock, ctx), firrtl.Utils.one))
- case Verification(op, info, clk, pred, msg) =>
+ args.map(a => convert(a, ctx, info)), convert(clock, ctx, info), firrtl.Utils.one, e.name))
+ case e @ Verification(_, op, info, clk, pred, msg) =>
val firOp = op match {
case Formal.Assert => fir.Formal.Assert
case Formal.Assume => fir.Formal.Assume
case Formal.Cover => fir.Formal.Cover
}
- Some(fir.Verification(firOp, convert(info), convert(clk, ctx),
- convert(pred, ctx), firrtl.Utils.one, fir.StringLit(msg)))
+ Some(fir.Verification(firOp, convert(info), convert(clk, ctx, info),
+ convert(pred, ctx, info), firrtl.Utils.one, fir.StringLit(msg), e.name))
case _ => None
}
@@ -173,7 +196,7 @@ private[chisel3] object Converter {
// Please see WhenFrame for more details
case None => cmds.head match {
case WhenBegin(info, pred) =>
- val when = fir.Conditionally(convert(info), convert(pred, ctx), fir.EmptyStmt, fir.EmptyStmt)
+ val when = fir.Conditionally(convert(info), convert(pred, ctx, info), fir.EmptyStmt, fir.EmptyStmt)
val frame = WhenFrame(when, acc, false)
rec(Queue.empty, frame +: scope)(cmds.tail)
case WhenEnd(info, depth, _) =>
@@ -221,7 +244,9 @@ private[chisel3] object Converter {
case d => d.specifiedDirection
}
- def extractType(data: Data, clearDir: Boolean = false): fir.Type = data match {
+ def extractType(data: Data, info: SourceInfo): fir.Type = extractType(data, false, info)
+
+ def extractType(data: Data, clearDir: Boolean, info: SourceInfo): fir.Type = data match {
case _: Clock => fir.ClockType
case _: AsyncReset => fir.AsyncResetType
case _: ResetType => fir.ResetType
@@ -231,16 +256,16 @@ private[chisel3] object Converter {
case d: FixedPoint => fir.FixedType(convert(d.width), convert(d.binaryPoint))
case d: Interval => fir.IntervalType(d.range.lowerBound, d.range.upperBound, d.range.firrtlBinaryPoint)
case d: Analog => fir.AnalogType(convert(d.width))
- case d: Vec[_] => fir.VectorType(extractType(d.sample_element, clearDir), d.length)
+ case d: Vec[_] => fir.VectorType(extractType(d.sample_element, clearDir, info), d.length)
case d: Record =>
val childClearDir = clearDir ||
d.specifiedDirection == SpecifiedDirection.Input || d.specifiedDirection == SpecifiedDirection.Output
def eltField(elt: Data): fir.Field = (childClearDir, firrtlUserDirOf(elt)) match {
- case (true, _) => fir.Field(elt.getRef.name, fir.Default, extractType(elt, true))
+ case (true, _) => fir.Field(getRef(elt, info).name, fir.Default, extractType(elt, true, info))
case (false, SpecifiedDirection.Unspecified | SpecifiedDirection.Output) =>
- fir.Field(elt.getRef.name, fir.Default, extractType(elt, false))
+ fir.Field(getRef(elt, info).name, fir.Default, extractType(elt, false, info))
case (false, SpecifiedDirection.Flip | SpecifiedDirection.Input) =>
- fir.Field(elt.getRef.name, fir.Flip, extractType(elt, false))
+ fir.Field(getRef(elt, info).name, fir.Flip, extractType(elt, false, info))
}
fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) })
}
@@ -251,6 +276,7 @@ private[chisel3] object Converter {
case StringParam(value) => fir.StringParam(name, fir.StringLit(value))
case RawParam(value) => fir.RawStringParam(name, value)
}
+
def convert(port: Port, topDir: SpecifiedDirection = SpecifiedDirection.Unspecified): fir.Port = {
val resolvedDir = SpecifiedDirection.fromParent(topDir, port.dir)
val dir = resolvedDir match {
@@ -261,8 +287,9 @@ private[chisel3] object Converter {
case SpecifiedDirection.Input | SpecifiedDirection.Output => true
case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip => false
}
- val tpe = extractType(port.id, clearDir)
- fir.Port(fir.NoInfo, port.id.getRef.name, dir, tpe)
+ val info = UnlocatableSourceInfo // Unfortunately there is no source locator for ports ATM
+ val tpe = extractType(port.id, clearDir, info)
+ fir.Port(fir.NoInfo, getRef(port.id, info).name, dir, tpe)
}
def convert(component: Component): fir.DefModule = component match {
@@ -275,5 +302,11 @@ private[chisel3] object Converter {
def convert(circuit: Circuit): fir.Circuit =
fir.Circuit(fir.NoInfo, circuit.components.map(convert), circuit.name)
+
+ // TODO Unclear if this should just be the default
+ def convertLazily(circuit: Circuit): fir.Circuit = {
+ val lazyModules = LazyList() ++ circuit.components
+ fir.Circuit(fir.NoInfo, lazyModules.map(convert), circuit.name)
+ }
}
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index 095c8a05..0b568548 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -3,13 +3,13 @@
package chisel3.internal.firrtl
import firrtl.{ir => fir}
-
import chisel3._
import chisel3.internal._
import chisel3.internal.sourceinfo.SourceInfo
import chisel3.experimental._
import _root_.firrtl.{ir => firrtlir}
-import _root_.firrtl.PrimOps
+import _root_.firrtl.{PrimOps, RenameMap}
+import _root_.firrtl.annotations.Annotation
import scala.collection.immutable.NumericRange
import scala.math.BigDecimal.RoundingMode
@@ -65,13 +65,19 @@ object PrimOp {
}
abstract class Arg {
- def fullName(ctx: Component): String = name
+ def localName: String = name
+ def contextualName(ctx: Component): String = name
+ def fullName(ctx: Component): String = contextualName(ctx)
def name: String
}
case class Node(id: HasId) extends Arg {
- override def fullName(ctx: Component): String = id.getOptionRef match {
- case Some(arg) => arg.fullName(ctx)
+ override def contextualName(ctx: Component): String = id.getOptionRef match {
+ case Some(arg) => arg.contextualName(ctx)
+ case None => id.instanceName
+ }
+ override def localName: String = id.getOptionRef match {
+ case Some(arg) => arg.localName
case None => id.instanceName
}
def name: String = id.getOptionRef match {
@@ -83,7 +89,7 @@ case class Node(id: HasId) extends Arg {
abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg {
private[chisel3] def forcedWidth = widthArg.known
private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth)
- override def fullName(ctx: Component): String = name
+ override def contextualName(ctx: Component): String = name
// Ensure the node representing this LitArg has a ref to it and a literal binding.
def bindLitArg[T <: Element](elem: T): T = {
elem.bind(ElementLitBinding(this))
@@ -91,6 +97,14 @@ abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg {
elem
}
+ /** Provides a mechanism that LitArgs can have their width adjusted
+ * to match other members of a VecLiteral
+ *
+ * @param newWidth the new width for this
+ * @return
+ */
+ def cloneWithWidth(newWidth: Width): this.type
+
protected def minWidth: Int
if (forcedWidth) {
require(widthArg.get >= minWidth,
@@ -106,6 +120,10 @@ case class ULit(n: BigInt, w: Width) extends LitArg(n, w) {
def name: String = "UInt" + width + "(\"h0" + num.toString(16) + "\")"
def minWidth: Int = 1 max n.bitLength
+ def cloneWithWidth(newWidth: Width): this.type = {
+ ULit(n, newWidth).asInstanceOf[this.type]
+ }
+
require(n >= 0, s"UInt literal ${n} is negative")
}
@@ -115,6 +133,10 @@ case class SLit(n: BigInt, w: Width) extends LitArg(n, w) {
s"asSInt(${ULit(unsigned, width).name})"
}
def minWidth: Int = 1 + n.bitLength
+
+ def cloneWithWidth(newWidth: Width): this.type = {
+ SLit(n, newWidth).asInstanceOf[this.type]
+ }
}
case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
@@ -123,6 +145,10 @@ case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n
s"asFixedPoint(${ULit(unsigned, width).name}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})"
}
def minWidth: Int = 1 + n.bitLength
+
+ def cloneWithWidth(newWidth: Width): this.type = {
+ FPLit(n, newWidth, binaryPoint).asInstanceOf[this.type]
+ }
}
case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
@@ -135,20 +161,45 @@ case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends Li
IntervalRange.getBound(isClosed = true, BigDecimal(n)), IntervalRange.getRangeWidth(binaryPoint))
}
def minWidth: Int = 1 + n.bitLength
+
+ def cloneWithWidth(newWidth: Width): this.type = {
+ IntervalLit(n, newWidth, binaryPoint).asInstanceOf[this.type]
+ }
}
case class Ref(name: String) extends Arg
+/** Arg for ports of Modules
+ * @param mod the module this port belongs to
+ * @param name the name of the port
+ */
case class ModuleIO(mod: BaseModule, name: String) extends Arg {
- override def fullName(ctx: Component): String =
+ override def contextualName(ctx: Component): String =
if (mod eq ctx.id) name else s"${mod.getRef.name}.$name"
}
+/** Ports of cloned modules (CloneModuleAsRecord)
+ * @param mod The original module for which these ports are a clone
+ * @param name the name of the module instance
+ */
+case class ModuleCloneIO(mod: BaseModule, name: String) extends Arg {
+ override def localName = ""
+ override def contextualName(ctx: Component): String =
+ // NOTE: mod eq ctx.id only occurs in Target and Named-related APIs
+ if (mod eq ctx.id) localName else name
+}
case class Slot(imm: Node, name: String) extends Arg {
- override def fullName(ctx: Component): String =
- if (imm.fullName(ctx).isEmpty) name else s"${imm.fullName(ctx)}.${name}"
+ override def contextualName(ctx: Component): String = {
+ val immName = imm.contextualName(ctx)
+ if (immName.isEmpty) name else s"$immName.$name"
+ }
+ override def localName: String = {
+ val immName = imm.localName
+ if (immName.isEmpty) name else s"$immName.$name"
+ }
}
case class Index(imm: Arg, value: Arg) extends Arg {
def name: String = s"[$value]"
- override def fullName(ctx: Component): String = s"${imm.fullName(ctx)}[${value.fullName(ctx)}]"
+ override def contextualName(ctx: Component): String = s"${imm.contextualName(ctx)}[${value.contextualName(ctx)}]"
+ override def localName: String = s"${imm.localName}[${value.localName}]"
}
object Width {
@@ -158,6 +209,7 @@ object Width {
sealed abstract class Width {
type W = Int
+ def min(that: Width): Width = this.op(that, _ min _)
def max(that: Width): Width = this.op(that, _ max _)
def + (that: Width): Width = this.op(that, _ + _)
def + (that: Int): Width = this.op(this, (a, b) => a + that)
@@ -734,14 +786,14 @@ 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 Port(id: Data, dir: SpecifiedDirection)
-case class Printf(sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Command
+case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition
object Formal extends Enumeration {
val Assert = Value("assert")
val Assume = Value("assume")
val Cover = Value("cover")
}
-case class Verification(op: Formal.Value, sourceInfo: SourceInfo, clock: Arg,
- predicate: Arg, message: String) extends Command
+case class Verification[T <: BaseSim](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg,
+ predicate: Arg, message: String) extends Definition
abstract class Component extends Arg {
def id: BaseModule
def name: String
@@ -750,4 +802,7 @@ abstract class Component extends Arg {
case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component
case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component
-case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation] = Seq.empty)
+case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) {
+ def firrtlAnnotations: Iterable[Annotation] = annotations.flatMap(_.toFirrtl.update(renames))
+
+}