summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/internal
diff options
context:
space:
mode:
authorJack Koenig2020-03-22 18:13:58 -0700
committerJack Koenig2020-03-25 19:17:15 -0700
commitfbf5e6f1a0e8bf535d465b748ad554575fe62156 (patch)
tree578858ab6d219ca6daf44cf87b73f75054989097 /chiselFrontend/src/main/scala/chisel3/internal
parentb2e004fb615a3c931d910a338b9faa99c1c975d7 (diff)
Rename subprojects to more canonical names
* Rename coreMacros to macros * Rename chiselFrontend to core Also make each subproject publish with "chisel3-" as a prefix
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/internal')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala333
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Binding.scala114
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Builder.scala452
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Error.scala213
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala264
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Namer.scala154
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala61
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala275
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala750
9 files changed, 0 insertions, 2616 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala
deleted file mode 100644
index 6b4c1070..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala
+++ /dev/null
@@ -1,333 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3.internal
-
-import chisel3._
-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._
-
-/**
-* BiConnect.connect executes a bidirectional connection element-wise.
-*
-* Note that the arguments are left and right (not source and sink) so the
-* intent is for the operation to be commutative.
-*
-* The connect operation will recurse down the left Data (with the right Data).
-* An exception will be thrown if a movement through the left cannot be matched
-* in the right (or if the right side has extra fields).
-*
-* See elemConnect for details on how the root connections are issued.
-*
-*/
-
-private[chisel3] object BiConnect {
- // scalastyle:off method.name public.methods.have.type
- // These are all the possible exceptions that can be thrown.
- // These are from element-level connection
- def BothDriversException =
- BiConnectException(": Both Left and Right are drivers")
- def NeitherDriverException =
- BiConnectException(": Neither Left nor Right is a driver")
- def UnknownDriverException =
- BiConnectException(": Locally unclear whether Left or Right (both internal)")
- def UnknownRelationException =
- BiConnectException(": Left or Right unavailable to current module.")
- // These are when recursing down aggregate types
- def MismatchedVecException =
- BiConnectException(": Left and Right are different length Vecs.")
- def MissingLeftFieldException(field: String) =
- BiConnectException(s".$field: Left Record missing field ($field).")
- def MissingRightFieldException(field: String) =
- BiConnectException(s": Right Record missing field ($field).")
- def MismatchedException(left: String, right: String) =
- BiConnectException(s": Left ($left) and Right ($right) have different types.")
- def AttachAlreadyBulkConnectedException(sourceInfo: SourceInfo) =
- BiConnectException(sourceInfo.makeMessage(": Analog previously bulk connected at " + _))
- def DontCareCantBeSink =
- BiConnectException(": DontCare cannot be a connection sink (LHS)")
- // scalastyle:on method.name public.methods.have.type
-
- /** This function is what recursively tries to connect a left and right together
- *
- * There is some cleverness in the use of internal try-catch to catch exceptions
- * during the recursive decent and then rethrow them with extra information added.
- * This gives the user a 'path' to where in the connections things went wrong.
- */
- def connect(sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Data, right: Data, context_mod: RawModule): Unit = { // scalastyle:ignore line.size.limit cyclomatic.complexity method.length
- (left, right) match {
- // Handle element case (root case)
- case (left_a: Analog, right_a: Analog) =>
- try {
- markAnalogConnected(sourceInfo, left_a, context_mod)
- markAnalogConnected(sourceInfo, right_a, context_mod)
- } catch { // convert attach exceptions to BiConnectExceptions
- case attach.AttachException(message) => throw BiConnectException(message)
- }
- attach.impl(Seq(left_a, right_a), context_mod)(sourceInfo)
- case (left_a: Analog, DontCare) =>
- try {
- markAnalogConnected(sourceInfo, left_a, context_mod)
- } catch { // convert attach exceptions to BiConnectExceptions
- case attach.AttachException(message) => throw BiConnectException(message)
- }
- pushCommand(DefInvalid(sourceInfo, left_a.lref))
- case (DontCare, right_a: Analog) => connect(sourceInfo, connectCompileOptions, right, left, context_mod)
- case (left_e: Element, right_e: Element) => {
- elemConnect(sourceInfo, connectCompileOptions, left_e, right_e, context_mod)
- // TODO(twigg): Verify the element-level classes are connectable
- }
- // Handle Vec case
- case (left_v: Vec[Data@unchecked], right_v: Vec[Data@unchecked]) => {
- if (left_v.length != right_v.length) {
- throw MismatchedVecException
- }
- for (idx <- 0 until left_v.length) {
- try {
- implicit val compileOptions = connectCompileOptions
- connect(sourceInfo, connectCompileOptions, left_v(idx), right_v(idx), context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
- }
- }
- }
- // Handle Vec connected to DontCare
- case (left_v: Vec[Data@unchecked], DontCare) => {
- for (idx <- 0 until left_v.length) {
- try {
- implicit val compileOptions = connectCompileOptions
- connect(sourceInfo, connectCompileOptions, left_v(idx), right, context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
- }
- }
- }
- // Handle DontCare connected to Vec
- case (DontCare, right_v: Vec[Data@unchecked]) => {
- for (idx <- 0 until right_v.length) {
- try {
- implicit val compileOptions = connectCompileOptions
- connect(sourceInfo, connectCompileOptions, left, right_v(idx), context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s"($idx)$message")
- }
- }
- }
- // 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 connected to DontCare (change to NotStrict)
- case (left_r: Record, DontCare) =>
- left_r.compileOptions match {
- case ExplicitCompileOptions.NotStrict =>
- left.bulkConnect(right)(sourceInfo, ExplicitCompileOptions.NotStrict)
- case _ =>
- // For each field in left, descend with right
- for ((field, left_sub) <- left_r.elements) {
- try {
- connect(sourceInfo, connectCompileOptions, left_sub, right, context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s".$field$message")
- }
- }
- }
- case (DontCare, right_r: Record) =>
- right_r.compileOptions match {
- case ExplicitCompileOptions.NotStrict =>
- left.bulkConnect(right)(sourceInfo, ExplicitCompileOptions.NotStrict)
- case _ =>
- // For each field in left, descend with right
- for ((field, right_sub) <- right_r.elements) {
- try {
- connect(sourceInfo, connectCompileOptions, left, right_sub, context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s".$field$message")
- }
- }
- }
-
- // Left and right are different subtypes of Data so fail
- case (left, right) => throw MismatchedException(left.toString, right.toString)
- }
- }
-
- // Do connection of two Records
- def recordConnect(sourceInfo: SourceInfo,
- connectCompileOptions: CompileOptions,
- left_r: Record,
- right_r: Record,
- context_mod: RawModule): Unit = {
- // Verify right has no extra fields that left doesn't have
- for((field, right_sub) <- right_r.elements) {
- if(!left_r.elements.isDefinedAt(field)) {
- if (connectCompileOptions.connectFieldsMustMatch) {
- throw MissingLeftFieldException(field)
- }
- }
- }
- // For each field in left, descend with right
- for((field, left_sub) <- left_r.elements) {
- try {
- right_r.elements.get(field) match {
- case Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod)
- case None => {
- if (connectCompileOptions.connectFieldsMustMatch) {
- throw MissingRightFieldException(field)
- }
- }
- }
- } catch {
- case BiConnectException(message) => throw BiConnectException(s".$field$message")
- }
- }
- }
-
-
- // These functions (finally) issue the connection operation
- // Issue with right as sink, left as source
- private def issueConnectL2R(left: Element, right: Element)(implicit sourceInfo: SourceInfo): Unit = {
- // Source and sink are ambiguous in the case of a Bi/Bulk Connect (<>).
- // If either is a DontCareBinding, just issue a DefInvalid for the other,
- // otherwise, issue a Connect.
- (left.topBinding, right.topBinding) match {
- case (lb: DontCareBinding, _) => pushCommand(DefInvalid(sourceInfo, right.lref))
- case (_, rb: DontCareBinding) => pushCommand(DefInvalid(sourceInfo, left.lref))
- case (_, _) => pushCommand(Connect(sourceInfo, right.lref, left.ref))
- }
- }
- // Issue with left as sink, right as source
- private def issueConnectR2L(left: Element, right: Element)(implicit sourceInfo: SourceInfo): Unit = {
- // Source and sink are ambiguous in the case of a Bi/Bulk Connect (<>).
- // If either is a DontCareBinding, just issue a DefInvalid for the other,
- // otherwise, issue a Connect.
- (left.topBinding, right.topBinding) match {
- case (lb: DontCareBinding, _) => pushCommand(DefInvalid(sourceInfo, right.lref))
- case (_, rb: DontCareBinding) => pushCommand(DefInvalid(sourceInfo, left.lref))
- case (_, _) => pushCommand(Connect(sourceInfo, left.lref, right.ref))
- }
- }
-
- // 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 = { // scalastyle:ignore line.size.limit cyclomatic.complexity method.length
- import BindingDirection.{Internal, Input, Output} // Using extensively so import these
- // 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)
- val right_mod: BaseModule = right.topBinding.location.getOrElse(context_mod)
-
- val left_direction = BindingDirection.from(left.topBinding, left.direction)
- val right_direction = BindingDirection.from(right.topBinding, right.direction)
-
- // CASE: Context is same module as left node and right node is in a child module
- if( (left_mod == context_mod) &&
- (right_mod._parent.map(_ == context_mod).getOrElse(false)) ) {
- // Thus, right node better be a port node and thus have a direction hint
- ((left_direction, right_direction): @unchecked) match {
- // CURRENT MOD CHILD MOD
- case (Input, Input) => issueConnectL2R(left, right)
- case (Internal, Input) => issueConnectL2R(left, right)
-
- case (Output, Output) => issueConnectR2L(left, right)
- case (Internal, Output) => issueConnectR2L(left, right)
-
- case (Input, Output) => throw BothDriversException
- case (Output, Input) => throw NeitherDriverException
- case (_, Internal) => throw UnknownRelationException
- }
- }
-
- // CASE: Context is same module as right node and left node is in child module
- else if( (right_mod == context_mod) &&
- (left_mod._parent.map(_ == context_mod).getOrElse(false)) ) {
- // Thus, left node better be a port node and thus have a direction hint
- ((left_direction, right_direction): @unchecked) match {
- // CHILD MOD CURRENT MOD
- case (Input, Input) => issueConnectR2L(left, right)
- case (Input, Internal) => issueConnectR2L(left, right)
-
- case (Output, Output) => issueConnectL2R(left, right)
- case (Output, Internal) => issueConnectL2R(left, right)
-
- case (Input, Output) => throw NeitherDriverException
- case (Output, Input) => throw BothDriversException
- case (Internal, _) => throw UnknownRelationException
- }
- }
-
- // CASE: Context is same module that both left node and right node are in
- else if( (context_mod == left_mod) && (context_mod == right_mod) ) {
- ((left_direction, right_direction): @unchecked) match {
- // CURRENT MOD CURRENT MOD
- case (Input, Output) => issueConnectL2R(left, right)
- case (Input, Internal) => issueConnectL2R(left, right)
- case (Internal, Output) => issueConnectL2R(left, right)
-
- case (Output, Input) => issueConnectR2L(left, right)
- case (Output, Internal) => issueConnectR2L(left, right)
- case (Internal, Input) => issueConnectR2L(left, right)
-
- case (Input, Input) => throw BothDriversException
- case (Output, Output) => throw BothDriversException
- case (Internal, Internal) => {
- if (connectCompileOptions.dontAssumeDirectionality) {
- throw UnknownDriverException
- } else {
- issueConnectR2L(left, right)
- }
- }
- }
- }
-
- // CASE: Context is the parent module of both the module containing left node
- // and the module containing right node
- // Note: This includes case when left and right in same module but in parent
- else if( (left_mod._parent.map(_ == context_mod).getOrElse(false)) &&
- (right_mod._parent.map(_ == context_mod).getOrElse(false))
- ) {
- // Thus both nodes must be ports and have a direction hint
- ((left_direction, right_direction): @unchecked) match {
- // CHILD MOD CHILD MOD
- case (Input, Output) => issueConnectR2L(left, right)
- case (Output, Input) => issueConnectL2R(left, right)
-
- case (Input, Input) => throw NeitherDriverException
- case (Output, Output) => throw BothDriversException
- case (_, Internal) =>
- if (connectCompileOptions.dontAssumeDirectionality) {
- throw UnknownRelationException
- } else {
- issueConnectR2L(left, right)
- }
- case (Internal, _) =>
- if (connectCompileOptions.dontAssumeDirectionality) {
- throw UnknownRelationException
- } else {
- issueConnectR2L(left, right)
- }
- }
- }
-
- // Not quite sure where left and right are compared to current module
- // so just error out
- else throw UnknownRelationException
- }
-
- // This function checks if analog element-level attaching is allowed, then marks the Analog as connected
- def markAnalogConnected(implicit sourceInfo: SourceInfo, analog: Analog, contextModule: RawModule): Unit = {
- analog.biConnectLocs.get(contextModule) match {
- case Some(sl) => throw AttachAlreadyBulkConnectedException(sl)
- case None => // Do nothing
- }
- // Mark bulk connected
- analog.biConnectLocs(contextModule) = sourceInfo
- }
-}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Binding.scala b/chiselFrontend/src/main/scala/chisel3/internal/Binding.scala
deleted file mode 100644
index 07c44f9f..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/Binding.scala
+++ /dev/null
@@ -1,114 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3.internal
-
-import chisel3._
-import chisel3.experimental.BaseModule
-import chisel3.internal.firrtl.LitArg
-
-/** Requires that a node is hardware ("bound")
- */
-object requireIsHardware {
- def apply(node: Data, msg: String = ""): Unit = {
- node._parent match { // Compatibility layer hack
- case Some(x: BaseModule) => x._compatAutoWrapPorts
- case _ =>
- }
- if (!node.isSynthesizable) {
- val prefix = if (msg.nonEmpty) s"$msg " else ""
- throw ExpectedHardwareException(s"$prefix'$node' must be hardware, " +
- "not a bare Chisel type. Perhaps you forgot to wrap it in Wire(_) or IO(_)?")
- }
- }
-}
-
-/** Requires that a node is a chisel type (not hardware, "unbound")
- */
-object requireIsChiselType {
- def apply(node: Data, msg: String = ""): Unit = if (node.isSynthesizable) {
- val prefix = if (msg.nonEmpty) s"$msg " else ""
- throw ExpectedChiselTypeException(s"$prefix'$node' must be a Chisel type, not hardware")
- }
-}
-
-// Element only direction used for the Binding system only.
-private[chisel3] sealed abstract class BindingDirection
-private[chisel3] object BindingDirection {
- /** Internal type or wire
- */
- case object Internal extends BindingDirection
- /** Module port with output direction
- */
- case object Output extends BindingDirection
- /** Module port with input direction
- */
- case object Input extends BindingDirection
-
- /** Determine the BindingDirection of an Element given its top binding and resolved direction.
- */
- def from(binding: TopBinding, direction: ActualDirection): BindingDirection = {
- binding match {
- case PortBinding(_) => direction match {
- case ActualDirection.Output => Output
- case ActualDirection.Input => Input
- case dir => throw new RuntimeException(s"Unexpected port element direction '$dir'")
- }
- case _ => Internal
- }
- }
-}
-
-// Location refers to 'where' in the Module hierarchy this lives
-sealed trait Binding {
- def location: Option[BaseModule]
-}
-// Top-level binding representing hardware, not a pointer to another binding (like ChildBinding)
-sealed trait TopBinding extends Binding
-
-// Constrained-ness refers to whether 'bound by Module boundaries'
-// An unconstrained binding, like a literal, can be read by everyone
-sealed trait UnconstrainedBinding extends TopBinding {
- def location: Option[BaseModule] = None
-}
-// A constrained binding can only be read/written by specific modules
-// Location will track where this Module is, and the bound object can be referenced in FIRRTL
-sealed trait ConstrainedBinding extends TopBinding {
- def enclosure: BaseModule
- def location: Option[BaseModule] = {
- // If an aspect is present, return the aspect module. Otherwise, return the enclosure module
- // This allows aspect modules to pretend to be enclosed modules for connectivity checking,
- // inside vs outside instance checking, etc.
- Builder.aspectModule(enclosure) match {
- case None => Some(enclosure)
- case Some(aspect) => Some(aspect)
- }
- }
-}
-
-// A binding representing a data that cannot be (re)assigned to.
-sealed trait ReadOnlyBinding extends TopBinding
-
-// TODO(twigg): Ops between unenclosed nodes can also be unenclosed
-// However, Chisel currently binds all op results to a module
-case class OpBinding(enclosure: RawModule) extends ConstrainedBinding with ReadOnlyBinding
-case class MemoryPortBinding(enclosure: RawModule) extends ConstrainedBinding
-case class PortBinding(enclosure: BaseModule) extends ConstrainedBinding
-case class RegBinding(enclosure: RawModule) extends ConstrainedBinding
-case class WireBinding(enclosure: RawModule) extends ConstrainedBinding
-
-case class ChildBinding(parent: Data) extends Binding {
- def location: Option[BaseModule] = parent.topBinding.location
-}
-/** Special binding for Vec.sample_element */
-case class SampleElementBinding[T <: Data](parent: Vec[T]) extends Binding {
- def location = parent.topBinding.location
-}
-// 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
-
-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
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
deleted file mode 100644
index 773a9ad1..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
+++ /dev/null
@@ -1,452 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3.internal
-
-import scala.util.DynamicVariable
-import scala.collection.mutable.ArrayBuffer
-import chisel3._
-import chisel3.experimental._
-import chisel3.internal.firrtl._
-import chisel3.internal.naming._
-import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
-
-import scala.collection.mutable
-
-private[chisel3] class Namespace(keywords: Set[String]) {
- private val names = collection.mutable.HashMap[String, Long]()
- for (keyword <- keywords)
- names(keyword) = 1
-
- private def rename(n: String): String = {
- val index = names(n)
- val tryName = s"${n}_${index}"
- names(n) = index + 1
- if (this contains tryName) rename(n) else tryName
- }
-
- private def sanitize(s: String, leadingDigitOk: Boolean = false): String = {
- // TODO what character set does FIRRTL truly support? using ANSI C for now
- def legalStart(c: Char) = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
- def legal(c: Char) = legalStart(c) || (c >= '0' && c <= '9')
- val res = s filter legal
- val headOk = (!res.isEmpty) && (leadingDigitOk || legalStart(res.head))
- if (headOk) res else s"_$res"
- }
-
- def contains(elem: String): Boolean = names.contains(elem)
-
- // leadingDigitOk is for use in fields of Records
- def name(elem: String, leadingDigitOk: Boolean = false): String = {
- val sanitized = sanitize(elem, leadingDigitOk)
- if (this contains sanitized) {
- name(rename(sanitized))
- } else {
- names(sanitized) = 1
- sanitized
- }
- }
-}
-
-private[chisel3] object Namespace {
- /** Constructs an empty Namespace */
- def empty: Namespace = new Namespace(Set.empty[String])
-}
-
-private[chisel3] class IdGen {
- private var counter = -1L
- def next: Long = {
- counter += 1
- counter
- }
-}
-
-/** Public API to access Node/Signal names.
- * currently, the node's name, the full path name, and references to its parent Module and component.
- * These are only valid once the design has been elaborated, and should not be used during its construction.
- */
-trait InstanceId {
- def instanceName: String
- def pathName: String
- def parentPathName: String
- def parentModName: String
- /** Returns a FIRRTL Named that refers to this object in the elaborated hardware graph */
- def toNamed: Named
- /** Returns a FIRRTL IsMember that refers to this object in the elaborated hardware graph */
- def toTarget: IsMember
- /** Returns a FIRRTL IsMember that refers to the absolute path to this object in the elaborated hardware graph */
- def toAbsoluteTarget: IsMember
-}
-
-private[chisel3] trait HasId extends InstanceId {
- private[chisel3] def _onModuleClose: Unit = {} // scalastyle:ignore method.name
- private[chisel3] val _parent: Option[BaseModule] = Builder.currentModule
- _parent.foreach(_.addId(this))
-
- private[chisel3] val _id: Long = Builder.idGen.next
-
- // TODO: remove this, but its removal seems to cause a nasty Scala compiler crash.
- override def hashCode: Int = super.hashCode()
- override def equals(that: Any): Boolean = super.equals(that)
-
- // Facilities for 'suggesting' a name to this.
- // Post-name hooks called to carry the suggestion to other candidates as needed
- private var suggested_name: Option[String] = None
- private val postname_hooks = scala.collection.mutable.ListBuffer.empty[String=>Unit]
- // Only takes the first suggestion!
- def suggestName(name: =>String): this.type = {
- if(suggested_name.isEmpty) suggested_name = Some(name)
- for(hook <- postname_hooks) { hook(name) }
- this
- }
- private[chisel3] def suggestedName: Option[String] = suggested_name
- private[chisel3] def addPostnameHook(hook: String=>Unit): Unit = postname_hooks += hook
-
- // Uses a namespace to convert suggestion into a true name
- // Will not do any naming if the reference already assigned.
- // (e.g. tried to suggest a name to part of a Record)
- private[chisel3] def forceName(default: =>String, namespace: Namespace): Unit =
- if(_ref.isEmpty) {
- val candidate_name = suggested_name.getOrElse(default)
- val available_name = namespace.name(candidate_name)
- setRef(Ref(available_name))
- }
-
- private var _ref: Option[Arg] = None
- private[chisel3] def setRef(imm: Arg): Unit = _ref = Some(imm)
- private[chisel3] def setRef(parent: HasId, name: String): Unit = setRef(Slot(Node(parent), name))
- private[chisel3] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index)))
- private[chisel3] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref))
- private[chisel3] def getRef: Arg = _ref.get
- private[chisel3] def getOptionRef: Option[Arg] = _ref
-
- // 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 => suggested_name.getOrElse("??")
- }
- 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(p) => s"${p.pathName}.$instanceName"
- }
- def parentPathName: String = _parent match {
- case Some(p) => p.pathName
- case None => throwException(s"$instanceName doesn't have a parent")
- }
- def parentModName: String = _parent match {
- 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 Some(p) => p.circuitName
- }
-
- private[chisel3] def getPublicFields(rootClass: Class[_]): Seq[java.lang.reflect.Method] = {
- // Suggest names to nodes using runtime reflection
- def getValNames(c: Class[_]): Set[String] = {
- if (c == rootClass) {
- Set()
- } else {
- getValNames(c.getSuperclass) ++ c.getDeclaredFields.map(_.getName)
- }
- }
- val valNames = getValNames(this.getClass)
- def isPublicVal(m: java.lang.reflect.Method) =
- m.getParameterTypes.isEmpty && valNames.contains(m.getName) && !m.getDeclaringClass.isAssignableFrom(rootClass)
- this.getClass.getMethods.sortWith(_.getName < _.getName).filter(isPublicVal(_))
- }
-}
-/** Holds the implementation of toNamed for Data and MemBase */
-private[chisel3] trait NamedComponent extends HasId {
- /** Returns a FIRRTL ComponentName that references this object
- * @note Should not be called until circuit elaboration is complete
- */
- final def toNamed: ComponentName =
- ComponentName(this.instanceName, ModuleName(this.parentModName, CircuitName(this.circuitName)))
-
- /** Returns a FIRRTL ReferenceTarget that references this object
- * @note Should not be called until circuit elaboration is complete
- */
- final def toTarget: ReferenceTarget = {
- val name = this.instanceName
- import _root_.firrtl.annotations.{Target, TargetToken}
- Target.toTargetTokens(name).toList match {
- case TargetToken.Ref(r) :: components => ReferenceTarget(this.circuitName, this.parentModName, Nil, r, components)
- case other =>
- throw _root_.firrtl.annotations.Target.NamedException(s"Cannot convert $name into [[ReferenceTarget]]: $other")
- }
- }
-
- final def toAbsoluteTarget: ReferenceTarget = {
- val localTarget = toTarget
- _parent match {
- case Some(parent) => parent.toAbsoluteTarget.ref(localTarget.ref).copy(component = localTarget.component)
- case None => localTarget
- }
- }
-}
-
-// Mutable global state for chisel that can appear outside a Builder context
-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()
-}
-
-private[chisel3] class DynamicContext() {
- val globalNamespace = Namespace.empty
- val components = ArrayBuffer[Component]()
- val annotations = ArrayBuffer[ChiselAnnotation]()
- var currentModule: Option[BaseModule] = None
-
- /** Contains a mapping from a elaborated module to their aspect
- * Set by [[ModuleAspect]]
- */
- val aspectModule: mutable.HashMap[BaseModule, BaseModule] = mutable.HashMap.empty[BaseModule, BaseModule]
-
- // 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
- var whenDepth: Int = 0 // Depth of when nesting
- var currentClock: Option[Clock] = None
- var currentReset: Option[Reset] = None
- val errors = new ErrorLog
- val namingStack = new NamingStack
-}
-
-//scalastyle:off number.of.methods
-private[chisel3] object Builder {
- // All global mutable state must be referenced via dynamicContextVar!!
- private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None)
- private def dynamicContext: DynamicContext = {
- require(dynamicContextVar.value.isDefined, "must be inside Builder context")
- dynamicContextVar.value.get
- }
-
- private val chiselContext = new DynamicVariable[ChiselContext](new ChiselContext)
-
- // Initialize any singleton objects before user code inadvertently inherits them.
- private def initializeSingletons(): Unit = {
- // This used to contain:
- // val dummy = core.DontCare
- // but this would occasionally produce hangs due to static initialization deadlock
- // when Builder initialization collided with chisel3.package initialization of the DontCare value.
- // See:
- // http://ternarysearch.blogspot.com/2013/07/static-initialization-deadlock.html
- // https://bugs.openjdk.java.net/browse/JDK-8037567
- // https://stackoverflow.com/questions/28631656/runnable-thread-state-but-in-object-wait
- }
-
- def namingStackOption: Option[NamingStack] = dynamicContextVar.value.map(_.namingStack)
-
- def idGen: IdGen = chiselContext.value.idGen
-
- def globalNamespace: Namespace = dynamicContext.globalNamespace
- def components: ArrayBuffer[Component] = dynamicContext.components
- def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations
- def namingStack: NamingStack = dynamicContext.namingStack
-
- def currentModule: Option[BaseModule] = dynamicContextVar.value match {
- case Some(dyanmicContext) => dynamicContext.currentModule
- case _ => None
- }
- def currentModule_=(target: Option[BaseModule]): Unit = {
- dynamicContext.currentModule = target
- }
- def aspectModule(module: BaseModule): Option[BaseModule] = dynamicContextVar.value match {
- case Some(dynamicContext) => dynamicContext.aspectModule.get(module)
- case _ => None
- }
- def addAspect(module: BaseModule, aspect: BaseModule): Unit = {
- dynamicContext.aspectModule += ((module, aspect))
- }
- def forcedModule: BaseModule = currentModule match {
- case Some(module) => module
- case None => throwException(
- "Error: Not in a Module. Likely cause: Missed Module() wrap or bare chisel API call."
- // A bare api call is, e.g. calling Wire() from the scala console).
- )
- }
- def referenceUserModule: RawModule = {
- currentModule match {
- case Some(module: RawModule) =>
- aspectModule(module) match {
- case Some(aspect: RawModule) => aspect
- case other => module
- }
- case _ => throwException(
- "Error: Not in a RawModule. Likely cause: Missed Module() wrap, bare chisel API call, or attempting to construct hardware inside a BlackBox." // scalastyle:ignore line.size.limit
- // A bare api call is, e.g. calling Wire() from the scala console).
- )
- }
- }
- def forcedUserModule: RawModule = currentModule match {
- case Some(module: RawModule) => module
- case _ => throwException(
- "Error: Not in a UserModule. Likely cause: Missed Module() wrap, bare chisel API call, or attempting to construct hardware inside a BlackBox." // scalastyle:ignore line.size.limit
- // A bare api call is, e.g. calling Wire() from the scala console).
- )
- }
- def readyForModuleConstr: Boolean = dynamicContext.readyForModuleConstr
- def readyForModuleConstr_=(target: Boolean): Unit = {
- dynamicContext.readyForModuleConstr = target
- }
- def whenDepth: Int = dynamicContext.whenDepth
- def whenDepth_=(target: Int): Unit = {
- dynamicContext.whenDepth = target
- }
- def currentClock: Option[Clock] = dynamicContext.currentClock
- def currentClock_=(newClock: Option[Clock]): Unit = {
- dynamicContext.currentClock = newClock
- }
-
- def currentReset: Option[Reset] = dynamicContext.currentReset
- def currentReset_=(newReset: Option[Reset]): Unit = {
- dynamicContext.currentReset = newReset
- }
-
- def forcedClock: Clock = currentClock.getOrElse(
- throwException("Error: No implicit clock.")
- )
- def forcedReset: Reset = currentReset.getOrElse(
- throwException("Error: No implicit reset.")
- )
-
- // TODO(twigg): Ideally, binding checks and new bindings would all occur here
- // However, rest of frontend can't support this yet.
- def pushCommand[T <: Command](c: T): T = {
- forcedUserModule.addCommand(c)
- c
- }
- def pushOp[T <: Data](cmd: DefPrim[T]): T = {
- // Bind each element of the returned Data to being a Op
- cmd.id.bind(OpBinding(forcedUserModule))
- 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.value.bundleStack.reverse.prefixLength { case (_, cname, mname, pos) =>
- pos >= stackEltsTop || stackElts(pos).getClassName != cname || stackElts(pos).getMethodName != mname
- }
- chiselContext.value.bundleStack.trimEnd(pruneLength)
-
- // Return the stack state before adding the most recent bundle
- val lastStack = chiselContext.value.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.value.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: HasId) => namer(id, prefix)
- case Some(elt) => nameRecursively(prefix, elt, namer)
- case (iter: Iterable[_]) if iter.hasDefiniteSize =>
- for ((elt, i) <- iter.zipWithIndex) {
- nameRecursively(s"${prefix}_${i}", elt, namer)
- }
- case _ => // Do nothing
- }
-
- def errors: ErrorLog = dynamicContext.errors
- def error(m: => String): Unit = if (dynamicContextVar.value.isDefined) errors.error(m)
- def warning(m: => String): Unit = if (dynamicContextVar.value.isDefined) errors.warning(m)
- def deprecated(m: => String, location: Option[String] = None): Unit =
- if (dynamicContextVar.value.isDefined) errors.deprecated(m, location)
-
- /** Record an exception as an error, and throw it.
- *
- * @param m exception message
- */
- @throws(classOf[ChiselException])
- def exception(m: => String): Unit = {
- error(m)
- throwException(m)
- }
-
- def build[T <: RawModule](f: => T): (Circuit, T) = {
- chiselContext.withValue(new ChiselContext) {
- dynamicContextVar.withValue(Some(new DynamicContext())) {
- errors.info("Elaborating design...")
- val mod = f
- mod.forceName(mod.name, globalNamespace)
- errors.checkpoint()
- errors.info("Done elaborating.")
-
- (Circuit(components.last.name, components, annotations), mod)
- }
- }
- }
- initializeSingletons()
-}
-
-/** Allows public access to the naming stack in Builder / DynamicContext, and handles invocations
- * outside a Builder context.
- * Necessary because naming macros expand in user code and don't have access into private[chisel3]
- * objects.
- */
-object DynamicNamingStack {
- def pushContext(): NamingContextInterface = {
- Builder.namingStackOption match {
- case Some(namingStack) => namingStack.pushContext()
- case None => DummyNamer
- }
- }
-
- def popReturnContext[T <: Any](prefixRef: T, until: NamingContextInterface): T = {
- until match {
- case DummyNamer =>
- require(Builder.namingStackOption.isEmpty,
- "Builder context must remain stable throughout a chiselName-annotated function invocation")
- case context: NamingContext =>
- require(Builder.namingStackOption.isDefined,
- "Builder context must remain stable throughout a chiselName-annotated function invocation")
- Builder.namingStackOption.get.popContext(prefixRef, context)
- }
- prefixRef
- }
-
- def length() : Int = Builder.namingStackOption.get.length
-}
-
-/** Casts BigInt to Int, issuing an error when the input isn't representable. */
-private[chisel3] object castToInt {
- def apply(x: BigInt, msg: String): Int = {
- val res = x.toInt
- require(x == res, s"$msg $x is too large to be represented as Int")
- res
- }
-}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
deleted file mode 100644
index 369da52e..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
+++ /dev/null
@@ -1,213 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3.internal
-
-import scala.annotation.tailrec
-import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
-
-class ChiselException(message: String, cause: Throwable = null) extends Exception(message, cause) {
-
- /** Package names whose stack trace elements should be trimmed when generating a trimmed stack trace */
- 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. */
- val builderName: String = chisel3.internal.Builder.getClass.getName
-
- /** Examine a [[Throwable]], to extract all its causes. Innermost cause is first.
- * @param throwable an exception to examine
- * @return a sequence of all the causes with innermost cause first
- */
- @tailrec
- private def getCauses(throwable: Throwable, acc: Seq[Throwable] = Seq.empty): Seq[Throwable] =
- throwable.getCause() match {
- case null => throwable +: acc
- case a => getCauses(a, throwable +: acc)
- }
-
- /** Returns true if an exception contains */
- private def containsBuilder(throwable: Throwable): Boolean =
- throwable.getStackTrace().collectFirst {
- case ste if ste.getClassName().startsWith(builderName) => throwable
- }.isDefined
-
- /** Examine this [[ChiselException]] and it's causes for the first [[Throwable]] that contains a stack trace including
- * a stack trace element whose declaring class is the [[builderName]]. If no such element exists, return this
- * [[ChiselException]].
- */
- private lazy val likelyCause: Throwable =
- getCauses(this).collectFirst{ case a if containsBuilder(a) => a }.getOrElse(this)
-
- /** For an exception, return a stack trace trimmed to user code only
- *
- * This does the following actions:
- *
- * 1. Trims the top of the stack trace while elements match [[blacklistPackages]]
- * 2. Trims the bottom of the stack trace until an element matches [[builderName]]
- * 3. Trims from the [[builderName]] all [[blacklistPackages]]
- *
- * @param throwable the exception whose stack trace should be trimmed
- * @return an array of stack trace elements
- */
- private def trimmedStackTrace(throwable: Throwable): Array[StackTraceElement] = {
- def isBlacklisted(ste: StackTraceElement) = {
- val packageName = ste.getClassName().takeWhile(_ != '.')
- blacklistPackages.contains(packageName)
- }
-
- val trimmedLeft = throwable.getStackTrace().view.dropWhile(isBlacklisted)
- val trimmedReverse = trimmedLeft.reverse
- .dropWhile(ste => !ste.getClassName.startsWith(builderName))
- .dropWhile(isBlacklisted)
- trimmedReverse.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)
-
- val sw = new java.io.StringWriter
- sw.write(likelyCause.toString + "\n")
- sw.write("\t...\n")
- trimmed.foreach(ste => sw.write(s"\tat $ste\n"))
- sw.write("\t... (Stack trace trimmed to user code only, rerun with --full-stacktrace if you wish to see the full stack trace)\n") // scalastyle:ignore line.size.limit
- sw.toString
- }
-}
-
-private[chisel3] object throwException {
- def apply(s: String, t: Throwable = null): Nothing =
- throw new ChiselException(s, t)
-}
-
-/** Records and reports runtime errors and warnings. */
-private[chisel3] object ErrorLog {
- val depTag = s"[${Console.BLUE}deprecated${Console.RESET}]"
- val warnTag = s"[${Console.YELLOW}warn${Console.RESET}]"
- val errTag = s"[${Console.RED}error${Console.RESET}]"
-}
-
-private[chisel3] class ErrorLog {
- /** Log an error message */
- def error(m: => String): Unit =
- errors += new Error(m, getUserLineNumber)
-
- /** Log a warning message */
- def warning(m: => String): Unit =
- errors += new Warning(m, getUserLineNumber)
-
- /** Emit an informational message */
- def info(m: String): Unit =
- println(new Info("[%2.3f] %s".format(elapsedTime/1e3, m), None)) // scalastyle:ignore regex
-
- /** Log a deprecation warning message */
- def deprecated(m: => String, location: Option[String]): Unit = {
- val sourceLoc = location match {
- case Some(loc) => loc
- case None => getUserLineNumber match {
- case Some(elt: StackTraceElement) => s"${elt.getFileName}:${elt.getLineNumber}"
- case None => "(unknown)"
- }
- }
-
- val thisEntry = (m, sourceLoc)
- deprecations += ((thisEntry, deprecations.getOrElse(thisEntry, 0) + 1))
- }
-
- /** Throw an exception if any errors have yet occurred. */
- def checkpoint(): Unit = {
- // scalastyle:off line.size.limit regex
- deprecations.foreach { case ((message, sourceLoc), count) =>
- println(s"${ErrorLog.depTag} $sourceLoc ($count calls): $message")
- }
- errors foreach println
-
- if (!deprecations.isEmpty) {
- println(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")""")
- }
-
- 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.")
- } else if (!allWarnings.isEmpty) {
- println(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.")
- }
-
- if (!allErrors.isEmpty) {
- throwException("Fatal errors during hardware elaboration")
- } else {
- // No fatal errors, clear accumulated warnings since they've been reported
- errors.clear()
- }
- // scalastyle:on line.size.limit regex
- }
-
- /** Returns the best guess at the first stack frame that belongs to user code.
- */
- private def getUserLineNumber = {
- def isChiselClassname(className: String): Boolean = {
- // List of classpath prefixes that are Chisel internals and should be ignored when looking for user code
- // utils are not part of internals and errors there can be reported
- val chiselPrefixes = Set(
- "java.",
- "scala.",
- "chisel3.internal.",
- "chisel3.experimental.",
- "chisel3.package$" // for some compatibility / deprecated types
- )
- !chiselPrefixes.filter(className.startsWith(_)).isEmpty
- }
-
- Thread.currentThread().getStackTrace.toList.dropWhile(
- // Get rid of everything in Chisel core
- ste => isChiselClassname(ste.getClassName)
- ).headOption
- }
-
- private val errors = ArrayBuffer[LogEntry]()
- private val deprecations = LinkedHashMap[(String, String), Int]()
-
- private val startTime = System.currentTimeMillis
- private def elapsedTime: Long = System.currentTimeMillis - startTime
-}
-
-private abstract class LogEntry(msg: => String, line: Option[StackTraceElement]) {
- def isFatal: Boolean = false
- def format: String
-
- override def toString: String = line match {
- case Some(l) => s"${format} ${l.getFileName}:${l.getLineNumber}: ${msg} in class ${l.getClassName}"
- case None => s"${format} ${msg}"
- }
-
- protected def tag(name: String, color: String): String =
- s"[${color}${name}${Console.RESET}]"
-}
-
-private class Error(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
- override def isFatal: Boolean = true
- def format: String = tag("error", Console.RED)
-}
-
-private class Warning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
- def format: String = tag("warn", Console.YELLOW)
-}
-
-private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
- def format: String = tag("info", Console.MAGENTA)
-}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala
deleted file mode 100644
index 41402021..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala
+++ /dev/null
@@ -1,264 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3.internal
-
-import chisel3._
-import chisel3.experimental.{Analog, BaseModule, EnumType, FixedPoint, Interval, UnsafeEnum}
-import chisel3.internal.Builder.pushCommand
-import chisel3.internal.firrtl.{Connect, DefInvalid}
-import scala.language.experimental.macros
-import chisel3.internal.sourceinfo.SourceInfo
-
-/**
-* MonoConnect.connect executes a mono-directional connection element-wise.
-*
-* Note that this isn't commutative. There is an explicit source and sink
-* already determined before this function is called.
-*
-* The connect operation will recurse down the left Data (with the right Data).
-* An exception will be thrown if a movement through the left cannot be matched
-* in the right. The right side is allowed to have extra Record fields.
-* Vecs must still be exactly the same size.
-*
-* See elemConnect for details on how the root connections are issued.
-*
-* Note that a valid sink must be writable so, one of these must hold:
-* - Is an internal writable node (Reg or Wire)
-* - Is an output of the current module
-* - Is an input of a submodule of the current module
-*
-* Note that a valid source must be readable so, one of these must hold:
-* - Is an internal readable node (Reg, Wire, Op)
-* - Is a literal
-* - Is a port of the current module or submodule of the current module
-*/
-
-private[chisel3] object MonoConnect {
- // scalastyle:off method.name public.methods.have.type
- // 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 UnknownRelationException =
- 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.")
- 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.")
- 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)")
- // scalastyle:on method.name public.methods.have.type
-
- /** This function is what recursively tries to connect a sink and source together
- *
- * There is some cleverness in the use of internal try-catch to catch exceptions
- * during the recursive decent and then rethrow them with extra information added.
- * This gives the user a 'path' to where in the connections things went wrong.
- */
- def connect( //scalastyle:off cyclomatic.complexity method.length
- sourceInfo: SourceInfo,
- connectCompileOptions: CompileOptions,
- sink: Data,
- source: Data,
- context_mod: RawModule): Unit =
- (sink, source) match {
-
- // Handle legal element cases, note (Bool, Bool) is caught by the first two, as Bool is a UInt
- case (sink_e: Bool, source_e: UInt) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: UInt, source_e: Bool) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: UInt, source_e: UInt) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: SInt, source_e: SInt) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: FixedPoint, source_e: FixedPoint) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: Interval, source_e: Interval) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: Clock, source_e: Clock) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: AsyncReset, source_e: AsyncReset) =>
- 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: 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) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
- case (sink_e: UnsafeEnum, source_e: UInt) =>
- elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod)
-
- // Handle Vec case
- case (sink_v: Vec[Data @unchecked], source_v: Vec[Data @unchecked]) =>
- if(sink_v.length != source_v.length) { throw MismatchedVecException }
- for(idx <- 0 until sink_v.length) {
- try {
- implicit val compileOptions = connectCompileOptions
- connect(sourceInfo, connectCompileOptions, sink_v(idx), source_v(idx), context_mod)
- } catch {
- case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message")
- }
- }
- // Handle Vec connected to DontCare. Apply the DontCare to individual elements.
- case (sink_v: Vec[Data @unchecked], DontCare) =>
- for(idx <- 0 until sink_v.length) {
- try {
- implicit val compileOptions = connectCompileOptions
- connect(sourceInfo, connectCompileOptions, sink_v(idx), source, context_mod)
- } catch {
- case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message")
- }
- }
-
- // Handle Record case
- case (sink_r: Record, source_r: Record) =>
- // For each field, descend with right
- for((field, sink_sub) <- sink_r.elements) {
- try {
- source_r.elements.get(field) match {
- case Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod)
- case None => {
- if (connectCompileOptions.connectFieldsMustMatch) {
- throw MissingFieldException(field)
- }
- }
- }
- } catch {
- case MonoConnectException(message) => throw MonoConnectException(s".$field$message")
- }
- }
- // Handle Record connected to DontCare. Apply the DontCare to individual elements.
- case (sink_r: Record, DontCare) =>
- // For each field, descend with right
- for((field, sink_sub) <- sink_r.elements) {
- try {
- connect(sourceInfo, connectCompileOptions, sink_sub, source, context_mod)
- } catch {
- case MonoConnectException(message) => throw MonoConnectException(s".$field$message")
- }
- }
-
- // Source is DontCare - it may be connected to anything. It generates a defInvalid for the sink.
- case (sink, DontCare) => pushCommand(DefInvalid(sourceInfo, sink.lref))
- // DontCare as a sink is illegal.
- case (DontCare, _) => throw DontCareCantBeSink
- // Analog is illegal in mono connections.
- case (_: Analog, _:Analog) => throw AnalogMonoConnectionException
- // Analog is illegal in mono connections.
- case (_: Analog, _) => throw AnalogCantBeMonoSink
- // Analog is illegal in mono connections.
- case (_, _: Analog) => throw AnalogCantBeMonoSource
- // Sink and source are different subtypes of data so fail
- case (sink, source) => throw MismatchedException(sink.toString, source.toString)
- }
-
- // This function (finally) issues the connection operation
- private def issueConnect(sink: Element, source: Element)(implicit sourceInfo: SourceInfo): Unit = {
- // If the source is a DontCare, generate a DefInvalid for the sink,
- // otherwise, issue a Connect.
- source.topBinding match {
- case b: DontCareBinding => pushCommand(DefInvalid(sourceInfo, sink.lref))
- case _ => pushCommand(Connect(sourceInfo, sink.lref, source.ref))
- }
- }
-
- // 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 = { // scalastyle:ignore line.size.limit
- import BindingDirection.{Internal, Input, Output} // Using extensively so import these
- // 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 source_mod: BaseModule = source.topBinding.location.getOrElse(context_mod)
-
- val sink_direction = BindingDirection.from(sink.topBinding, sink.direction)
- val source_direction = BindingDirection.from(source.topBinding, source.direction)
-
- // CASE: Context is same module that both left node and right node are in
- if( (context_mod == sink_mod) && (context_mod == source_mod) ) {
- ((sink_direction, source_direction): @unchecked) match {
- // SINK SOURCE
- // CURRENT MOD CURRENT MOD
- case (Output, _) => issueConnect(sink, source)
- case (Internal, _) => issueConnect(sink, source)
- case (Input, _) => throw UnwritableSinkException
- }
- }
-
- // CASE: Context is same module as sink node and right node is in a child module
- else if( (sink_mod == context_mod) &&
- (source_mod._parent.map(_ == context_mod).getOrElse(false)) ) {
- // Thus, right node better be a port node and thus have a direction
- ((sink_direction, source_direction): @unchecked) match {
- // SINK SOURCE
- // CURRENT MOD CHILD MOD
- case (Internal, Output) => issueConnect(sink, source)
- case (Internal, Input) => issueConnect(sink, source)
- case (Output, Output) => issueConnect(sink, source)
- case (Output, Input) => issueConnect(sink, source)
- case (_, Internal) => {
- if (!(connectCompileOptions.dontAssumeDirectionality)) {
- issueConnect(sink, source)
- } else {
- throw UnreadableSourceException
- }
- }
- case (Input, Output) if (!(connectCompileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink) // scalastyle:ignore line.size.limit
- case (Input, _) => throw UnwritableSinkException
- }
- }
-
- // CASE: Context is same module as source node and sink node is in child module
- else if( (source_mod == context_mod) &&
- (sink_mod._parent.map(_ == context_mod).getOrElse(false)) ) {
- // Thus, left node better be a port node and thus have a direction
- ((sink_direction, source_direction): @unchecked) match {
- // SINK SOURCE
- // CHILD MOD CURRENT MOD
- case (Input, _) => issueConnect(sink, source)
- case (Output, _) => throw UnwritableSinkException
- case (Internal, _) => throw UnwritableSinkException
- }
- }
-
- // CASE: Context is the parent module of both the module containing sink node
- // and the module containing source node
- // Note: This includes case when sink and source in same module but in parent
- else if( (sink_mod._parent.map(_ == context_mod).getOrElse(false)) &&
- (source_mod._parent.map(_ == context_mod).getOrElse(false))
- ) {
- // Thus both nodes must be ports and have a direction
- ((sink_direction, source_direction): @unchecked) match {
- // SINK SOURCE
- // CHILD MOD CHILD MOD
- case (Input, Input) => issueConnect(sink, source)
- case (Input, Output) => issueConnect(sink, source)
- case (Output, _) => throw UnwritableSinkException
- case (_, Internal) => {
- if (!(connectCompileOptions.dontAssumeDirectionality)) {
- issueConnect(sink, source)
- } else {
- throw UnreadableSourceException
- }
- }
- case (Internal, _) => throw UnwritableSinkException
- }
- }
-
- // Not quite sure where left and right are compared to current module
- // so just error out
- else throw UnknownRelationException
- }
-}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Namer.scala b/chiselFrontend/src/main/scala/chisel3/internal/Namer.scala
deleted file mode 100644
index 999971a4..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/Namer.scala
+++ /dev/null
@@ -1,154 +0,0 @@
-// See LICENSE for license details.
-
-// This file contains part of the implementation of the naming static annotation system.
-
-package chisel3.internal.naming
-import chisel3.experimental.NoChiselNamePrefix
-
-import scala.collection.mutable.Stack
-import scala.collection.mutable.ListBuffer
-
-import scala.collection.JavaConversions._
-
-import java.util.IdentityHashMap
-
-/** Recursive Function Namer overview
- *
- * In every function, creates a NamingContext object, which associates all vals with a string name
- * suffix, for example:
- * val myValName = SomeStatement()
- * produces the entry in items:
- * {ref of SomeStatement(), "myValName"}
- *
- * This is achieved with a macro transforming:
- * val myValName = SomeStatement()
- * statements into a naming call:
- * val myValName = context.name(SomeStatement(), "myValName")
- *
- * The context is created from a global dynamic context stack at the beginning of each function.
- * At the end of each function call, the completed context is added to its parent context and
- * associated with the return value (whose name at an enclosing function call will form the prefix
- * for all named objects).
- *
- * When the naming context prefix is given, it will name all of its items with the prefix and the
- * associated suffix name. Then, it will check its descendants for sub-contexts with references
- * matching the item reference, and if there is a match, it will (recursively) give the
- * sub-context a prefix of its current prefix plus the item reference suffix.
- *
- * Note that for Modules, the macro will insert a naming context prefix call with an empty prefix,
- * starting the recursive naming process.
- */
-
-/** Base class for naming contexts, providing the basic API consisting of naming calls and
- * ability to take descendant naming contexts.
- */
-sealed trait NamingContextInterface {
- /** Suggest a name (that will be propagated to FIRRTL) for an object, then returns the object
- * itself (so this can be inserted transparently anywhere).
- * Is a no-op (so safe) when applied on objects that aren't named, including non-Chisel data
- * types.
- */
- def name[T](obj: T, name: String): T
-
- /** Gives this context a naming prefix (which may be empty, "", for a top-level Module context)
- * so that actual naming calls (HasId.suggestName) can happen.
- * Recursively names descendants, for those whose return value have an associated name.
- */
- def namePrefix(prefix: String)
-}
-
-/** Dummy implementation to allow for naming annotations in a non-Builder context.
- */
-object DummyNamer extends NamingContextInterface {
- def name[T](obj: T, name: String): T = obj
-
- def namePrefix(prefix: String): Unit = {
- }
-}
-
-/** Actual namer functionality.
- */
-class NamingContext extends NamingContextInterface {
- val descendants = new IdentityHashMap[AnyRef, ListBuffer[NamingContext]]()
- val anonymousDescendants = ListBuffer[NamingContext]()
- val items = ListBuffer[(AnyRef, String)]()
- var closed = false // a sanity check to ensure no more name() calls are done after name_prefix
-
- /** Adds a NamingContext object as a descendant - where its contained objects will have names
- * prefixed with the name given to the reference object, if the reference object is named in the
- * scope of this context.
- */
- def addDescendant(ref: Any, descendant: NamingContext) {
- ref match {
- case ref: AnyRef =>
- descendants.getOrElseUpdate(ref, ListBuffer[NamingContext]()) += descendant
- case _ => anonymousDescendants += descendant
- }
- }
-
- def name[T](obj: T, name: String): T = {
- assert(!closed, "Can't name elements after name_prefix called")
- obj match {
- case _: NoChiselNamePrefix => // Don't name things with NoChiselNamePrefix
- case ref: AnyRef => items += ((ref, name))
- case _ =>
- }
- obj
- }
-
- def namePrefix(prefix: String): Unit = {
- closed = true
- for ((ref, suffix) <- items) {
- // First name the top-level object
- chisel3.internal.Builder.nameRecursively(prefix + suffix, ref, (id, name) => id.suggestName(name))
-
- // Then recurse into descendant contexts
- if (descendants.containsKey(ref)) {
- for (descendant <- descendants.get(ref)) {
- descendant.namePrefix(prefix + suffix + "_")
- }
- descendants.remove(ref)
- }
- }
-
- for (descendant <- descendants.values().flatten) {
- // Where we have a broken naming link, just ignore the missing parts
- descendant.namePrefix(prefix)
- }
- for (descendant <- anonymousDescendants) {
- descendant.namePrefix(prefix)
- }
- }
-}
-
-/** Class for the (global) naming stack object, which provides a way to push and pop naming
- * contexts as functions are called / finished.
- */
-class NamingStack {
- val namingStack = Stack[NamingContext]()
-
- /** Creates a new naming context, where all items in the context will have their names prefixed
- * with some yet-to-be-determined prefix from object names in an enclosing scope.
- */
- def pushContext(): NamingContext = {
- val context = new NamingContext
- namingStack.push(context)
- context
- }
-
- /** Called at the end of a function, popping the current naming context, adding it to the
- * enclosing context's descendants, and passing through the prefix naming reference.
- * Every instance of push_context() must have a matching pop_context().
- *
- * Will assert out if the context being popped isn't the topmost on the stack.
- */
- def popContext[T <: Any](prefixRef: T, until: NamingContext): Unit = {
- assert(namingStack.top == until)
- namingStack.pop()
- if (!namingStack.isEmpty) {
- namingStack.top.addDescendant(prefixRef, until)
- }
- }
-
- def length() : Int = namingStack.length
-}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala b/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala
deleted file mode 100644
index f1130db4..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/SourceInfo.scala
+++ /dev/null
@@ -1,61 +0,0 @@
-// See LICENSE for license details.
-
-// This file contains macros for adding source locators at the point of invocation.
-//
-// This is not part of coreMacros to disallow this macro from being implicitly invoked in Chisel
-// frontend (and generating source locators in Chisel core), which is almost certainly a bug.
-//
-// Note: While these functions and definitions are not private (macros can't be
-// private), these are NOT meant to be part of the public API (yet) and no
-// forward compatibility guarantees are made.
-// A future revision may stabilize the source locator API to allow library
-// writers to append source locator information at the point of a library
-// function invocation.
-
-package chisel3.internal.sourceinfo
-
-import scala.language.experimental.macros
-import scala.reflect.macros.blackbox.Context
-
-/** Abstract base class for generalized source information.
- */
-sealed trait SourceInfo {
- /** A prettier toString
- *
- * Make a useful message if SourceInfo is available, nothing otherwise
- */
- def makeMessage(f: String => String): String
-}
-
-sealed trait NoSourceInfo extends SourceInfo {
- def makeMessage(f: String => String): String = ""
-}
-
-/** For when source info can't be generated because of a technical limitation, like for Reg because
- * Scala macros don't support named or default arguments.
- */
-case object UnlocatableSourceInfo extends NoSourceInfo
-
-/** For when source info isn't generated because the function is deprecated and we're lazy.
- */
-case object DeprecatedSourceInfo extends NoSourceInfo
-
-/** For FIRRTL lines from a Scala source line.
- */
-case class SourceLine(filename: String, line: Int, col: Int) extends SourceInfo {
- def makeMessage(f: String => String): String = f(s"@[$filename $line:$col]")
-}
-
-/** Provides a macro that returns the source information at the invocation point.
- */
-object SourceInfoMacro {
- def generate_source_info(c: Context): c.Tree = {
- import c.universe._
- val p = c.enclosingPosition
- q"_root_.chisel3.internal.sourceinfo.SourceLine(${p.source.file.name}, ${p.line}, ${p.column})"
- }
-}
-
-object SourceInfo {
- implicit def materialize: SourceInfo = macro SourceInfoMacro.generate_source_info
-}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
deleted file mode 100644
index 5c1d6935..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
+++ /dev/null
@@ -1,275 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3.internal.firrtl
-import chisel3._
-import chisel3.experimental._
-import chisel3.internal.sourceinfo.{NoSourceInfo, SourceLine, SourceInfo}
-import firrtl.{ir => fir}
-import chisel3.internal.{castToInt, throwException}
-
-import scala.annotation.tailrec
-import scala.collection.immutable.Queue
-
-private[chisel3] object Converter {
- // TODO modeled on unpack method on Printable, refactor?
- def unpack(pable: Printable, ctx: Component): (String, Seq[Arg]) = pable match {
- case Printables(pables) =>
- val (fmts, args) = pables.map(p => unpack(p, ctx)).unzip
- (fmts.mkString, args.flatten.toSeq)
- case PString(str) => (str.replaceAll("%", "%%"), List.empty)
- case format: FirrtlFormat =>
- ("%" + format.specifier, List(format.bits.ref))
- case Name(data) => (data.ref.name, List.empty)
- case FullName(data) => (data.ref.fullName(ctx), List.empty)
- case Percent => ("%%", List.empty)
- }
-
- 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"))
- }
-
- def convert(op: PrimOp): fir.PrimOp = firrtl.PrimOps.fromString(op.name)
-
- def convert(dir: MemPortDirection): firrtl.MPortDir = dir match {
- case MemPortDirection.INFER => firrtl.MInfer
- case MemPortDirection.READ => firrtl.MRead
- case MemPortDirection.WRITE => firrtl.MWrite
- case MemPortDirection.RDWR => firrtl.MReadWrite
- }
-
- // TODO
- // * Memoize?
- // * Move into the Chisel IR?
- def convert(arg: Arg, ctx: Component): fir.Expression = arg match { // scalastyle:ignore cyclomatic.complexity
- case Node(id) =>
- convert(id.getRef, ctx)
- case Ref(name) =>
- fir.Reference(name, fir.UnknownType)
- case Slot(imm, name) =>
- fir.SubField(convert(imm, ctx), name, fir.UnknownType)
- case Index(imm, ILit(idx)) =>
- fir.SubIndex(convert(imm, ctx), castToInt(idx, "Index"), fir.UnknownType)
- case Index(imm, value) =>
- fir.SubAccess(convert(imm, ctx), convert(value, ctx), fir.UnknownType)
- case ModuleIO(mod, name) =>
- // scalastyle:off if.brace
- if (mod eq ctx.id) fir.Reference(name, fir.UnknownType)
- else fir.SubField(fir.Reference(mod.getRef.name, fir.UnknownType), name, fir.UnknownType)
- // scalastyle:on if.brace
- 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)
- 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 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 lit = bp.asInstanceOf[KnownBinaryPoint].value
- fir.DoPrim(firrtl.PrimOps.AsInterval, Seq(uint), Seq(n, n, lit), fir.UnknownType)
- case lit: ILit =>
- throwException(s"Internal Error! Unexpected ILit: $lit")
- }
-
- /** Convert Commands that map 1:1 to Statements */
- def convertSimpleCommand(cmd: Command, ctx: Component): Option[fir.Statement] = cmd match { // scalastyle:ignore cyclomatic.complexity line.size.limit
- case e: DefPrim[_] =>
- val consts = e.args.collect { case ILit(i) => i }
- val args = e.args.flatMap {
- case _: ILit => None
- case other => Some(convert(other, ctx))
- }
- val expr = e.op.name match {
- case "mux" =>
- assert(args.size == 3, s"Mux with unexpected args: $args")
- fir.Mux(args(0), args(1), args(2), fir.UnknownType)
- case _ =>
- fir.DoPrim(convert(e.op), args, consts, fir.UnknownType)
- }
- Some(fir.DefNode(convert(e.sourceInfo), e.name, expr))
- case e @ DefWire(info, id) =>
- Some(fir.DefWire(convert(info), e.name, extractType(id)))
- 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)))
- 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)))
- case e @ DefMemory(info, id, t, size) =>
- Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, false))
- case e @ DefSeqMemory(info, id, t, size, ruw) =>
- Some(firrtl.CDefMemory(convert(info), e.name, extractType(t), size, true, ruw))
- case e: DefMemPort[_] =>
- 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)))
- case Connect(info, loc, exp) =>
- Some(fir.Connect(convert(info), convert(loc, ctx), convert(exp, ctx)))
- case BulkConnect(info, loc, exp) =>
- Some(fir.PartialConnect(convert(info), convert(loc, ctx), convert(exp, ctx)))
- case Attach(info, locs) =>
- Some(fir.Attach(convert(info), locs.map(l => convert(l, ctx))))
- case DefInvalid(info, arg) =>
- Some(fir.IsInvalid(convert(info), convert(arg, ctx)))
- 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) =>
- 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 _ => None
- }
-
- /** Internal datastructure to help translate Chisel's flat Command structure to FIRRTL's AST
- *
- * In particular, when scoping is translated from flat with begin end to a nested datastructure
- *
- * @param when Current when Statement, holds info, condition, and consequence as they are
- * available
- * @param outer Already converted Statements that precede the current when block in the scope in
- * which the when is defined (ie. 1 level up from the scope inside the when)
- * @param alt Indicates if currently processing commands in the alternate (else) of the when scope
- */
- // TODO we should probably have a different structure in the IR to close elses
- private case class WhenFrame(when: fir.Conditionally, outer: Queue[fir.Statement], alt: Boolean)
-
- /** Convert Chisel IR Commands into FIRRTL Statements
- *
- * @note ctx is needed because references to ports translate differently when referenced within
- * the module in which they are defined vs. parent modules
- * @param cmds Chisel IR Commands to convert
- * @param ctx Component (Module) context within which we are translating
- * @return FIRRTL Statement that is equivalent to the input cmds
- */
- def convert(cmds: Seq[Command], ctx: Component): fir.Statement = { // scalastyle:ignore cyclomatic.complexity
- @tailrec
- // scalastyle:off if.brace
- def rec(acc: Queue[fir.Statement],
- scope: List[WhenFrame])
- (cmds: Seq[Command]): Seq[fir.Statement] = {
- if (cmds.isEmpty) {
- assert(scope.isEmpty)
- acc
- } else convertSimpleCommand(cmds.head, ctx) match {
- // Most Commands map 1:1
- case Some(stmt) =>
- rec(acc :+ stmt, scope)(cmds.tail)
- // When scoping logic does not map 1:1 and requires pushing/popping WhenFrames
- // Please see WhenFrame for more details
- case None => cmds.head match {
- case WhenBegin(info, pred) =>
- val when = fir.Conditionally(convert(info), convert(pred, ctx), fir.EmptyStmt, fir.EmptyStmt)
- val frame = WhenFrame(when, acc, false)
- rec(Queue.empty, frame +: scope)(cmds.tail)
- case WhenEnd(info, depth, _) =>
- val frame = scope.head
- val when = if (frame.alt) frame.when.copy(alt = fir.Block(acc))
- else frame.when.copy(conseq = fir.Block(acc))
- // Check if this when has an else
- cmds.tail.headOption match {
- case Some(AltBegin(_)) =>
- assert(!frame.alt, "Internal Error! Unexpected when structure!") // Only 1 else per when
- rec(Queue.empty, frame.copy(when = when, alt = true) +: scope.tail)(cmds.drop(2))
- case _ => // Not followed by otherwise
- // If depth > 0 then we need to close multiple When scopes so we add a new WhenEnd
- // If we're nested we need to add more WhenEnds to ensure each When scope gets
- // properly closed
- val cmdsx = if (depth > 0) WhenEnd(info, depth - 1, false) +: cmds.tail else cmds.tail
- rec(frame.outer :+ when, scope.tail)(cmdsx)
- }
- case OtherwiseEnd(info, depth) =>
- val frame = scope.head
- val when = frame.when.copy(alt = fir.Block(acc))
- // TODO For some reason depth == 1 indicates the last closing otherwise whereas
- // depth == 0 indicates last closing when
- val cmdsx = if (depth > 1) OtherwiseEnd(info, depth - 1) +: cmds.tail else cmds.tail
- rec(scope.head.outer :+ when, scope.tail)(cmdsx)
- }
- }
- }
- // scalastyle:on if.brace
- fir.Block(rec(Queue.empty, List.empty)(cmds))
- }
-
- def convert(width: Width): fir.Width = width match {
- case UnknownWidth() => fir.UnknownWidth
- case KnownWidth(value) => fir.IntWidth(value)
- }
-
- def convert(bp: BinaryPoint): fir.Width = bp match {
- case UnknownBinaryPoint => fir.UnknownWidth
- case KnownBinaryPoint(value) => fir.IntWidth(value)
- }
-
- private def firrtlUserDirOf(d: Data): SpecifiedDirection = d match {
- case d: Vec[_] =>
- SpecifiedDirection.fromParent(d.specifiedDirection, firrtlUserDirOf(d.sample_element))
- case d => d.specifiedDirection
- }
-
- def extractType(data: Data, clearDir: Boolean = false): fir.Type = data match { // scalastyle:ignore cyclomatic.complexity line.size.limit
- case _: Clock => fir.ClockType
- case _: AsyncReset => fir.AsyncResetType
- case _: ResetType => fir.ResetType
- case d: EnumType => fir.UIntType(convert(d.width))
- case d: UInt => fir.UIntType(convert(d.width))
- case d: SInt => fir.SIntType(convert(d.width))
- case d: FixedPoint => fir.FixedType(convert(d.width), convert(d.binaryPoint))
- case d: Interval => fir.IntervalType(d.range.lowerBound, d.range.upperBound, d.range.firrtlBinaryPoint)
- case d: Analog => fir.AnalogType(convert(d.width))
- case d: Vec[_] => fir.VectorType(extractType(d.sample_element, clearDir), 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 (false, SpecifiedDirection.Unspecified | SpecifiedDirection.Output) =>
- fir.Field(elt.getRef.name, fir.Default, extractType(elt, false))
- case (false, SpecifiedDirection.Flip | SpecifiedDirection.Input) =>
- fir.Field(elt.getRef.name, fir.Flip, extractType(elt, false))
- }
- fir.BundleType(d.elements.toIndexedSeq.reverse.map { case (_, e) => eltField(e) })
- }
-
- def convert(name: String, param: Param): fir.Param = param match {
- case IntParam(value) => fir.IntParam(name, value)
- case DoubleParam(value) => fir.DoubleParam(name, value)
- 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 {
- case SpecifiedDirection.Unspecified | SpecifiedDirection.Output => fir.Output
- case SpecifiedDirection.Flip | SpecifiedDirection.Input => fir.Input
- }
- val clearDir = resolvedDir match {
- 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)
- }
-
- def convert(component: Component): fir.DefModule = component match {
- case ctx @ DefModule(_, name, ports, cmds) =>
- fir.Module(fir.NoInfo, name, ports.map(p => convert(p)), convert(cmds.toList, ctx))
- case ctx @ DefBlackBox(id, name, ports, topDir, params) =>
- fir.ExtModule(fir.NoInfo, name, ports.map(p => convert(p, topDir)), id.desiredName,
- params.map { case (name, p) => convert(name, p) }.toSeq)
- }
-
- def convert(circuit: Circuit): fir.Circuit =
- fir.Circuit(fir.NoInfo, circuit.components.map(convert), circuit.name)
-}
-
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
deleted file mode 100644
index d98bebcd..00000000
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ /dev/null
@@ -1,750 +0,0 @@
-// See LICENSE for license details.
-
-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 scala.collection.immutable.NumericRange
-import scala.math.BigDecimal.RoundingMode
-
-// scalastyle:off number.of.types
-
-case class PrimOp(name: String) {
- override def toString: String = name
-}
-
-object PrimOp {
- val AddOp = PrimOp("add")
- val SubOp = PrimOp("sub")
- val TailOp = PrimOp("tail")
- val HeadOp = PrimOp("head")
- val TimesOp = PrimOp("mul")
- val DivideOp = PrimOp("div")
- val RemOp = PrimOp("rem")
- val ShiftLeftOp = PrimOp("shl")
- val ShiftRightOp = PrimOp("shr")
- val DynamicShiftLeftOp = PrimOp("dshl")
- val DynamicShiftRightOp = PrimOp("dshr")
- val BitAndOp = PrimOp("and")
- val BitOrOp = PrimOp("or")
- val BitXorOp = PrimOp("xor")
- val BitNotOp = PrimOp("not")
- val ConcatOp = PrimOp("cat")
- val BitsExtractOp = PrimOp("bits")
- val LessOp = PrimOp("lt")
- val LessEqOp = PrimOp("leq")
- val GreaterOp = PrimOp("gt")
- val GreaterEqOp = PrimOp("geq")
- val EqualOp = PrimOp("eq")
- val PadOp = PrimOp("pad")
- val NotEqualOp = PrimOp("neq")
- val NegOp = PrimOp("neg")
- val MultiplexOp = PrimOp("mux")
- val AndReduceOp = PrimOp("andr")
- val OrReduceOp = PrimOp("orr")
- val XorReduceOp = PrimOp("xorr")
- val ConvertOp = PrimOp("cvt")
- val AsUIntOp = PrimOp("asUInt")
- val AsSIntOp = PrimOp("asSInt")
- val AsFixedPointOp = PrimOp("asFixedPoint")
- val AsIntervalOp = PrimOp("asInterval")
- val WrapOp = PrimOp("wrap")
- val SqueezeOp = PrimOp("squz")
- val ClipOp = PrimOp("clip")
- val SetBinaryPoint = PrimOp("setp")
- val IncreasePrecision = PrimOp("incp")
- val DecreasePrecision = PrimOp("decp")
- val AsClockOp = PrimOp("asClock")
- val AsAsyncResetOp = PrimOp("asAsyncReset")
-}
-
-abstract class Arg {
- def fullName(ctx: Component): String = name
- 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)
- case None => id.suggestedName.getOrElse("??")
- }
- def name: String = id.getOptionRef match {
- case Some(arg) => arg.name
- case None => id.suggestedName.getOrElse("??")
- }
-}
-
-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
- // 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))
- elem.setRef(this)
- elem
- }
-
- protected def minWidth: Int
- if (forcedWidth) {
- require(widthArg.get >= minWidth,
- s"The literal value ${num} was elaborated with a specified width of ${widthArg.get} bits, but at least ${minWidth} bits are required.") // scalastyle:ignore line.size.limit
- }
-}
-
-case class ILit(n: BigInt) extends Arg {
- def name: String = n.toString
-}
-
-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
-
- require(n >= 0, s"UInt literal ${n} is negative")
-}
-
-case class SLit(n: BigInt, w: Width) extends LitArg(n, w) {
- def name: String = {
- val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
- s"asSInt(${ULit(unsigned, width).name})"
- }
- def minWidth: Int = 1 + n.bitLength
-}
-
-case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
- def name: String = {
- val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
- s"asFixedPoint(${ULit(unsigned, width).name}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})"
- }
- def minWidth: Int = 1 + n.bitLength
-}
-
-case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
- def name: String = {
- val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n
- s"asInterval(${ULit(unsigned, width).name}, ${n}, ${n}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})"
- }
- val range: IntervalRange = {
- new IntervalRange(IntervalRange.getBound(isClosed = true, BigDecimal(n)),
- IntervalRange.getBound(isClosed = true, BigDecimal(n)), IntervalRange.getRangeWidth(binaryPoint))
- }
- def minWidth: Int = 1 + n.bitLength
-}
-
-case class Ref(name: String) extends Arg
-case class ModuleIO(mod: BaseModule, name: String) extends Arg {
- override def fullName(ctx: Component): String =
- if (mod eq ctx.id) name else s"${mod.getRef.name}.$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}"
-}
-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)}]"
-}
-
-object Width {
- def apply(x: Int): Width = KnownWidth(x)
- def apply(): Width = UnknownWidth()
-}
-
-sealed abstract class Width {
- type W = Int
- 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)
- def shiftRight(that: Int): Width = this.op(this, (a, b) => 0 max (a - that))
- def dynamicShiftLeft(that: Width): Width =
- this.op(that, (a, b) => a + (1 << b) - 1)
-
- def known: Boolean
- def get: W
- protected def op(that: Width, f: (W, W) => W): Width
-}
-
-sealed case class UnknownWidth() extends Width {
- def known: Boolean = false
- def get: Int = None.get
- def op(that: Width, f: (W, W) => W): Width = this
- override def toString: String = ""
-}
-
-sealed case class KnownWidth(value: Int) extends Width {
- require(value >= 0)
- def known: Boolean = true
- def get: Int = value
- def op(that: Width, f: (W, W) => W): Width = that match {
- case KnownWidth(x) => KnownWidth(f(value, x))
- case _ => that
- }
- override def toString: String = s"<${value.toString}>"
-}
-
-object BinaryPoint {
- def apply(x: Int): BinaryPoint = KnownBinaryPoint(x)
- def apply(): BinaryPoint = UnknownBinaryPoint
-}
-
-sealed abstract class BinaryPoint {
- type W = Int
- def max(that: BinaryPoint): BinaryPoint = this.op(that, _ max _)
- def + (that: BinaryPoint): BinaryPoint = this.op(that, _ + _)
- def + (that: Int): BinaryPoint = this.op(this, (a, b) => a + that)
- def shiftRight(that: Int): BinaryPoint = this.op(this, (a, b) => 0 max (a - that))
- def dynamicShiftLeft(that: BinaryPoint): BinaryPoint =
- this.op(that, (a, b) => a + (1 << b) - 1)
-
- def known: Boolean
- def get: W
- protected def op(that: BinaryPoint, f: (W, W) => W): BinaryPoint
-}
-
-case object UnknownBinaryPoint extends BinaryPoint {
- def known: Boolean = false
- def get: Int = None.get
- def op(that: BinaryPoint, f: (W, W) => W): BinaryPoint = this
- override def toString: String = ""
-}
-
-sealed case class KnownBinaryPoint(value: Int) extends BinaryPoint {
- def known: Boolean = true
- def get: Int = value
- def op(that: BinaryPoint, f: (W, W) => W): BinaryPoint = that match {
- case KnownBinaryPoint(x) => KnownBinaryPoint(f(value, x))
- case _ => that
- }
- override def toString: String = s"<<${value.toString}>>"
-}
-
-
-sealed abstract class MemPortDirection(name: String) {
- override def toString: String = name
-}
-object MemPortDirection {
- object READ extends MemPortDirection("read")
- object WRITE extends MemPortDirection("write")
- object RDWR extends MemPortDirection("rdwr")
- object INFER extends MemPortDirection("infer")
-}
-
-sealed trait RangeType {
- def getWidth: Width
-
- def * (that: IntervalRange): IntervalRange
- def +& (that: IntervalRange): IntervalRange
- def -& (that: IntervalRange): IntervalRange
- def << (that: Int): IntervalRange
- def >> (that: Int): IntervalRange
- def << (that: KnownWidth): IntervalRange
- def >> (that: KnownWidth): IntervalRange
- def merge(that: IntervalRange): IntervalRange
-}
-
-object IntervalRange {
- /** Creates an IntervalRange, this is used primarily by the range interpolator macro
- * @param lower lower bound
- * @param upper upper bound
- * @param firrtlBinaryPoint binary point firrtl style
- * @return
- */
- def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, firrtlBinaryPoint: firrtlir.Width): IntervalRange = {
- new IntervalRange(lower, upper, firrtlBinaryPoint)
- }
-
- def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, binaryPoint: BinaryPoint): IntervalRange = {
- new IntervalRange(lower, upper, IntervalRange.getBinaryPoint(binaryPoint))
- }
-
- def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, binaryPoint: Int): IntervalRange = {
- IntervalRange(lower, upper, BinaryPoint(binaryPoint))
- }
-
- /** Returns an IntervalRange appropriate for a signed value of the given width
- * @param binaryPoint number of bits of mantissa
- * @return
- */
- def apply(binaryPoint: BinaryPoint): IntervalRange = {
- IntervalRange(firrtlir.UnknownBound, firrtlir.UnknownBound, binaryPoint)
- }
-
- /** Returns an IntervalRange appropriate for a signed value of the given width
- * @param width number of bits to have in the interval
- * @param binaryPoint number of bits of mantissa
- * @return
- */
- def apply(width: Width, binaryPoint: BinaryPoint = 0.BP): IntervalRange = {
- val range = width match {
- case KnownWidth(w) =>
- val nearestPowerOf2 = BigInt("1" + ("0" * (w - 1)), 2)
- IntervalRange(
- firrtlir.Closed(BigDecimal(-nearestPowerOf2)), firrtlir.Closed(BigDecimal(nearestPowerOf2 - 1)), binaryPoint
- )
- case _ =>
- IntervalRange(firrtlir.UnknownBound, firrtlir.UnknownBound, binaryPoint)
- }
- range
- }
-
- def unapply(arg: IntervalRange): Option[(firrtlir.Bound, firrtlir.Bound, BinaryPoint)] = {
- return Some((arg.lower, arg.upper, arg.binaryPoint))
- }
-
- def getBound(isClosed: Boolean, value: String): firrtlir.Bound = {
- if(value == "?") {
- firrtlir.UnknownBound
- }
- else if(isClosed) {
- firrtlir.Closed(BigDecimal(value))
- }
- else {
- firrtlir.Open(BigDecimal(value))
- }
- }
-
- def getBound(isClosed: Boolean, value: BigDecimal): firrtlir.Bound = {
- if(isClosed) {
- firrtlir.Closed(value)
- }
- else {
- firrtlir.Open(value)
- }
- }
-
- def getBound(isClosed: Boolean, value: Int): firrtlir.Bound = {
- getBound(isClosed, (BigDecimal(value)))
- }
-
- def getBinaryPoint(s: String): firrtlir.Width = {
- firrtlir.UnknownWidth
- }
-
- def getBinaryPoint(n: Int): firrtlir.Width = {
- if(n < 0) {
- firrtlir.UnknownWidth
- }
- else {
- firrtlir.IntWidth(n)
- }
- }
- def getBinaryPoint(n: BinaryPoint): firrtlir.Width = {
- n match {
- case UnknownBinaryPoint => firrtlir.UnknownWidth
- case KnownBinaryPoint(w) => firrtlir.IntWidth(w)
- }
- }
-
- def getRangeWidth(w: Width): firrtlir.Width = {
- if(w.known) {
- firrtlir.IntWidth(w.get)
- }
- else {
- firrtlir.UnknownWidth
- }
- }
- def getRangeWidth(binaryPoint: BinaryPoint): firrtlir.Width = {
- if(binaryPoint.known) {
- firrtlir.IntWidth(binaryPoint.get)
- }
- else {
- firrtlir.UnknownWidth
- }
- }
-
- //scalastyle:off method.name
- def Unknown: IntervalRange = range"[?,?].?"
-}
-
-
-sealed class IntervalRange(
- val lowerBound: firrtlir.Bound,
- val upperBound: firrtlir.Bound,
- private[chisel3] val firrtlBinaryPoint: firrtlir.Width)
- extends firrtlir.IntervalType(lowerBound, upperBound, firrtlBinaryPoint)
- with RangeType {
-
- (lowerBound, upperBound) match {
- case (firrtlir.Open(begin), firrtlir.Open(end)) =>
- if(begin >= end) throw new ChiselException(s"Invalid range with ${serialize}")
- binaryPoint match {
- case KnownBinaryPoint(bp) =>
- if(begin >= end - (BigDecimal(1) / BigDecimal(BigInt(1) << bp))) {
- throw new ChiselException(s"Invalid range with ${serialize}")
- }
- case _ =>
- }
- case (firrtlir.Open(begin), firrtlir.Closed(end)) =>
- if(begin >= end) throw new ChiselException(s"Invalid range with ${serialize}")
- case (firrtlir.Closed(begin), firrtlir.Open(end)) =>
- if(begin >= end) throw new ChiselException(s"Invalid range with ${serialize}")
- case (firrtlir.Closed(begin), firrtlir.Closed(end)) =>
- if(begin > end) throw new ChiselException(s"Invalid range with ${serialize}")
- case _ =>
- }
-
- //scalastyle:off cyclomatic.complexity
- override def toString: String = {
- val binaryPoint = firrtlBinaryPoint match {
- case firrtlir.IntWidth(n) => s"$n"
- case _ => "?"
- }
- val lowerBoundString = lowerBound match {
- case firrtlir.Closed(l) => s"[$l"
- case firrtlir.Open(l) => s"($l"
- case firrtlir.UnknownBound => s"[?"
- }
- val upperBoundString = upperBound match {
- case firrtlir.Closed(l) => s"$l]"
- case firrtlir.Open(l) => s"$l)"
- case firrtlir.UnknownBound => s"?]"
- }
- s"""range"$lowerBoundString,$upperBoundString.$binaryPoint""""
- }
-
- val increment: Option[BigDecimal] = firrtlBinaryPoint match {
- case firrtlir.IntWidth(bp) =>
- Some(BigDecimal(math.pow(2, -bp.doubleValue)))
- case _ => None
- }
-
- /** If possible returns the lowest possible value for this Interval
- * @return
- */
- val getLowestPossibleValue: Option[BigDecimal] = {
- increment match {
- case Some(inc) =>
- lower match {
- case firrtlir.Closed(n) => Some(n)
- case firrtlir.Open(n) => Some(n + inc)
- case _ => None
- }
- case _ =>
- None
- }
- }
-
- /** If possible returns the highest possible value for this Interval
- * @return
- */
- val getHighestPossibleValue: Option[BigDecimal] = {
- increment match {
- case Some(inc) =>
- upper match {
- case firrtlir.Closed(n) => Some(n)
- case firrtlir.Open(n) => Some(n - inc)
- case _ => None
- }
- case _ =>
- None
- }
- }
-
- /** Return a Seq of the possible values for this range
- * Mostly to be used for testing
- * @return
- */
- def getPossibleValues: NumericRange[BigDecimal] = {
- (getLowestPossibleValue, getHighestPossibleValue, increment) match {
- case (Some(low), Some(high), Some(inc)) => (low to high by inc)
- case (_, _, None) =>
- throw new ChiselException(s"BinaryPoint unknown. Cannot get possible values from IntervalRange $toString")
- case _ =>
- throw new ChiselException(s"Unknown Bound. Cannot get possible values from IntervalRange $toString")
-
- }
- }
-
- override def getWidth: Width = {
- width match {
- case firrtlir.IntWidth(n) => KnownWidth(n.toInt)
- case firrtlir.UnknownWidth => UnknownWidth()
- }
- }
-
- private def doFirrtlOp(op: firrtlir.PrimOp, that: IntervalRange): IntervalRange = {
- PrimOps.set_primop_type(
- firrtlir.DoPrim(op,
- Seq(firrtlir.Reference("a", this), firrtlir.Reference("b", that)), Nil,firrtlir.UnknownType)
- ).tpe match {
- case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point)
- case other => sys.error("BAD!")
- }
- }
-
- private def doFirrtlDynamicShift(that: UInt, isLeft: Boolean): IntervalRange = {
- val uinttpe = that.widthOption match {
- case None => firrtlir.UIntType(firrtlir.UnknownWidth)
- case Some(w) => firrtlir.UIntType(firrtlir.IntWidth(w))
- }
- val op = if(isLeft) PrimOps.Dshl else PrimOps.Dshr
- PrimOps.set_primop_type(
- firrtlir.DoPrim(op,
- Seq(firrtlir.Reference("a", this), firrtlir.Reference("b", uinttpe)), Nil,firrtlir.UnknownType)
- ).tpe match {
- case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point)
- case other => sys.error("BAD!")
- }
- }
-
- private def doFirrtlOp(op: firrtlir.PrimOp, that: Int): IntervalRange = {
- PrimOps.set_primop_type(
- firrtlir.DoPrim(op,
- Seq(firrtlir.Reference("a", this)), Seq(BigInt(that)), firrtlir.UnknownType)
- ).tpe match {
- case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point)
- case other => sys.error("BAD!")
- }
- }
-
- /** Multiply this by that, here we return a fully unknown range,
- * firrtl's range inference can figure this out
- * @param that
- * @return
- */
- override def *(that: IntervalRange): IntervalRange = {
- doFirrtlOp(PrimOps.Mul, that)
- }
-
- /** Add that to this, here we return a fully unknown range,
- * firrtl's range inference can figure this out
- * @param that
- * @return
- */
- override def +&(that: IntervalRange): IntervalRange = {
- doFirrtlOp(PrimOps.Add, that)
- }
-
- /** Subtract that from this, here we return a fully unknown range,
- * firrtl's range inference can figure this out
- * @param that
- * @return
- */
- override def -&(that: IntervalRange): IntervalRange = {
- doFirrtlOp(PrimOps.Sub, that)
- }
-
- private def adjustBoundValue(value: BigDecimal, binaryPointValue: Int): BigDecimal = {
- if(binaryPointValue >= 0) {
- val maskFactor = BigDecimal(1 << binaryPointValue)
- val a = (value * maskFactor)
- val b = a.setScale(0, RoundingMode.DOWN)
- val c = b / maskFactor
- c
- } else {
- value
- }
- }
-
- private def adjustBound(bound: firrtlir.Bound, binaryPoint: BinaryPoint): firrtlir.Bound = {
- binaryPoint match {
- case KnownBinaryPoint(binaryPointValue) =>
- bound match {
- case firrtlir.Open(value) => firrtlir.Open(adjustBoundValue(value, binaryPointValue))
- case firrtlir.Closed(value) => firrtlir.Closed(adjustBoundValue(value, binaryPointValue))
- case _ => bound
- }
- case _ => firrtlir.UnknownBound
- }
- }
-
- /** Creates a new range with the increased precision
- *
- * @param newBinaryPoint
- * @return
- */
- def incPrecision(newBinaryPoint: BinaryPoint): IntervalRange = {
- newBinaryPoint match {
- case KnownBinaryPoint(that) =>
- doFirrtlOp(PrimOps.IncP, that)
- case _ =>
- throwException(s"$this.incPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know")
- }
- }
-
- /** Creates a new range with the decreased precision
- *
- * @param newBinaryPoint
- * @return
- */
- def decPrecision(newBinaryPoint: BinaryPoint): IntervalRange = {
- newBinaryPoint match {
- case KnownBinaryPoint(that) =>
- doFirrtlOp(PrimOps.DecP, that)
- case _ =>
- throwException(s"$this.decPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know")
- }
- }
-
- /** Creates a new range with the given binary point, adjusting precision
- * on bounds as necessary
- *
- * @param newBinaryPoint
- * @return
- */
- def setPrecision(newBinaryPoint: BinaryPoint): IntervalRange = {
- newBinaryPoint match {
- case KnownBinaryPoint(that) =>
- doFirrtlOp(PrimOps.SetP, that)
- case _ =>
- throwException(s"$this.setPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know")
- }
- }
-
- /** Shift this range left, i.e. shifts the min and max by the specified amount
- * @param that
- * @return
- */
- override def <<(that: Int): IntervalRange = {
- doFirrtlOp(PrimOps.Shl, that)
- }
-
- /** Shift this range left, i.e. shifts the min and max by the known width
- * @param that
- * @return
- */
- override def <<(that: KnownWidth): IntervalRange = {
- <<(that.value)
- }
-
- /** Shift this range left, i.e. shifts the min and max by value
- * @param that
- * @return
- */
- def <<(that: UInt): IntervalRange = {
- doFirrtlDynamicShift(that, isLeft = true)
- }
-
- /** Shift this range right, i.e. shifts the min and max by the specified amount
- * @param that
- * @return
- */
- override def >>(that: Int): IntervalRange = {
- doFirrtlOp(PrimOps.Shr, that)
- }
-
- /** Shift this range right, i.e. shifts the min and max by the known width
- * @param that
- * @return
- */
- override def >>(that: KnownWidth): IntervalRange = {
- >>(that.value)
- }
-
- /** Shift this range right, i.e. shifts the min and max by value
- * @param that
- * @return
- */
- def >>(that: UInt): IntervalRange = {
- doFirrtlDynamicShift(that, isLeft = false)
- }
-
- /**
- * Squeeze returns the intersection of the ranges this interval and that Interval
- * @param that
- * @return
- */
- def squeeze(that: IntervalRange): IntervalRange = {
- doFirrtlOp(PrimOps.Squeeze, that)
- }
-
- /**
- * Wrap the value of this [[Interval]] into the range of a different Interval with a presumably smaller range.
- * @param that
- * @return
- */
- def wrap(that: IntervalRange): IntervalRange = {
- doFirrtlOp(PrimOps.Wrap, that)
- }
-
- /**
- * Clip the value of this [[Interval]] into the range of a different Interval with a presumably smaller range.
- * @param that
- * @return
- */
- def clip(that: IntervalRange): IntervalRange = {
- doFirrtlOp(PrimOps.Clip, that)
- }
-
- /** merges the ranges of this and that, basically takes lowest low, highest high and biggest bp
- * set unknown if any of this or that's value of above is unknown
- * Like an union but will slurp up points in between the two ranges that were part of neither
- * @param that
- * @return
- */
- override def merge(that: IntervalRange): IntervalRange = {
- val lowest = (this.getLowestPossibleValue, that.getLowestPossibleValue) match {
- case (Some(l1), Some(l2)) =>
- if(l1 < l2) { this.lower } else { that.lower }
- case _ =>
- firrtlir.UnknownBound
- }
- val highest = (this.getHighestPossibleValue, that.getHighestPossibleValue) match {
- case (Some(l1), Some(l2)) =>
- if(l1 >= l2) { this.lower } else { that.lower }
- case _ =>
- firrtlir.UnknownBound
- }
- val newBinaryPoint = (this.firrtlBinaryPoint, that.firrtlBinaryPoint) match {
- case (firrtlir.IntWidth(b1), firrtlir.IntWidth(b2)) =>
- if(b1 > b2) { firrtlir.IntWidth(b1)} else { firrtlir.IntWidth(b2) }
- case _ =>
- firrtlir.UnknownWidth
- }
- IntervalRange(lowest, highest, newBinaryPoint)
- }
-
- def binaryPoint: BinaryPoint = {
- firrtlBinaryPoint match {
- case firrtlir.IntWidth(n) =>
- assert(n < Int.MaxValue, s"binary point value $n is out of range")
- KnownBinaryPoint(n.toInt)
- case _ => UnknownBinaryPoint
- }
- }
-}
-
-abstract class Command {
- def sourceInfo: SourceInfo
-}
-abstract class Definition extends Command {
- def id: HasId
- def name: String = id.getRef.name
-}
-// scalastyle:off line.size.limit
-case class DefPrim[T <: Data](sourceInfo: SourceInfo, id: T, op: PrimOp, args: Arg*) extends Definition
-case class DefInvalid(sourceInfo: SourceInfo, arg: Arg) extends Command
-case class DefWire(sourceInfo: SourceInfo, id: Data) extends Definition
-case class DefReg(sourceInfo: SourceInfo, id: Data, clock: Arg) extends Definition
-case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg, init: Arg) extends Definition
-case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition
-case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition
-case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition
-case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition
-case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command
-case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command
-case class AltBegin(sourceInfo: SourceInfo) extends Command
-case class OtherwiseEnd(sourceInfo: SourceInfo, firrtlDepth: Int) extends Command
-case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
-case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command
-case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command
-case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
-case class Stop(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
-abstract class Component extends Arg {
- def id: BaseModule
- def name: String
- def ports: Seq[Port]
-}
-case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component
-case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component
-
-case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation] = Seq.empty)