diff --git a/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala index e122f13a7f0..f49deff48b8 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/BiConnect.scala @@ -61,11 +61,20 @@ private[chisel3] object BiConnect { // Handle element case (root case) case (left_a: Analog, right_a: Analog) => try { - analogAttach(sourceInfo, left_a, right_a, context_mod) - } catch { - // If attach fails, convert to BiConnectException + 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 @@ -312,21 +321,13 @@ private[chisel3] object BiConnect { else throw UnknownRelationException } - // This function checks if analog element-level attaching is allowed - // Then it either issues it or throws the appropriate exception. - def analogAttach(implicit sourceInfo: SourceInfo, left: Analog, right: Analog, contextModule: RawModule): Unit = { - // Error if left or right is BICONNECTED in the current module already - for (elt <- left :: right :: Nil) { - elt.biConnectLocs.get(contextModule) match { - case Some(sl) => throw AttachAlreadyBulkConnectedException(sl) - case None => // Do nothing - } + // 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 } - - // Do the attachment - attach.impl(Seq(left, right), contextModule) // Mark bulk connected - left.biConnectLocs(contextModule) = sourceInfo - right.biConnectLocs(contextModule) = sourceInfo + analog.biConnectLocs(contextModule) = sourceInfo } } diff --git a/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala index 91f1bfd8e48..e07f980d837 100644 --- a/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala +++ b/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala @@ -3,7 +3,7 @@ package chisel3.internal import chisel3._ -import chisel3.experimental.{BaseModule, EnumType, FixedPoint, RawModule, UnsafeEnum} +import chisel3.experimental.{Analog, BaseModule, EnumType, FixedPoint, RawModule, UnsafeEnum} import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.{Connect, DefInvalid} import scala.language.experimental.macros @@ -52,6 +52,12 @@ private[chisel3] object MonoConnect { 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 @@ -142,6 +148,12 @@ private[chisel3] object MonoConnect { 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) } diff --git a/src/test/scala/chiselTests/AnalogSpec.scala b/src/test/scala/chiselTests/AnalogSpec.scala index b262074c257..c78c8c0ed1c 100644 --- a/src/test/scala/chiselTests/AnalogSpec.scala +++ b/src/test/scala/chiselTests/AnalogSpec.scala @@ -169,6 +169,29 @@ class AnalogSpec extends ChiselFlatSpec { wires(0) <> wires(2) }) } + a [ChiselException] should be thrownBy { + elaborate(new Module { + val io = IO(new Bundle {}) + val wires = List.fill(2)(Wire(Analog(32.W))) + wires(0) <> DontCare + wires(0) <> wires(1) + }) + } + } + + it should "allow DontCare connection" in { + elaborate(new Module { + val io = IO(new Bundle { + val a = Analog(1.W) + }) + io.a := DontCare + }) + elaborate(new Module { + val io = IO(new Bundle { + val a = Analog(1.W) + }) + io.a <> DontCare + }) } it should "work with 3 blackboxes attached" in { diff --git a/src/test/scala/chiselTests/ChiselSpec.scala b/src/test/scala/chiselTests/ChiselSpec.scala index 0a0eb3f0944..5973cb631e3 100644 --- a/src/test/scala/chiselTests/ChiselSpec.scala +++ b/src/test/scala/chiselTests/ChiselSpec.scala @@ -147,7 +147,7 @@ class ChiselTestUtilitiesSpec extends ChiselFlatSpec { class ChiselPropSpec extends PropSpec with ChiselRunners with PropertyChecks with Matchers { // Constrain the default number of instances generated for every use of forAll. - implicit override val generatorDrivenConfig = + implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 8, minSize = 1, sizeRange = 3) // Generator for small positive integers.