summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala246
1 files changed, 0 insertions, 246 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
deleted file mode 100644
index 6a4ae9bf..00000000
--- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
+++ /dev/null
@@ -1,246 +0,0 @@
-// See LICENSE for license details.
-
-package chisel3.core
-
-import chisel3.internal.ChiselException
-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
-*/
-
-object MonoConnect {
- // scalastyle:off method.name public.methods.have.type
- // These are all the possible exceptions that can be thrown.
- case class MonoConnectException(message: String) extends ChiselException(message)
- // 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)")
- // 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: Clock, source_e: Clock) =>
- 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
- // 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
- }
-}