summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala
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/BiConnect.scala
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/BiConnect.scala')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala333
1 files changed, 0 insertions, 333 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
- }
-}