Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/src/main/scala/chisel3/domain/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ final class Type private[domain] (val domain: Domain) extends Element { self =>

override def cloneType: this.type = new Type(domain).asInstanceOf[this.type]

override def toString: String = s"${domain.name}.Type"

override def toPrintable: Printable =
throwException(s"'domain.Type' does not support hardware printing" + this._errorContext)

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/chisel3/domain/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ package object domain {
* @param source the source of the forward
*/
def define[A <: domain.Type](sink: A, source: A)(implicit sourceInfo: SourceInfo): Unit = {
Builder.pushCommand(ir.DomainDefine(sourceInfo, sink.lref, source.ref))
chisel3.internal.MonoConnect.domainDefine(sourceInfo, sink, source, Builder.referenceUserContainer)
}

/** Unsafe cast to a variadic list of domains.
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/scala/chisel3/internal/BiConnect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ private[chisel3] object BiConnect {
}
pushCommand(DefInvalid(sourceInfo, left_a.lref(sourceInfo)))
case (DontCare, right_a: Analog) => connect(sourceInfo, right, left, context_mod)
// Two domains are bi-connected at the root. `domain_define` has no
// direction, so :<=/<> are simply lowered to the same node as `domain.define`.
case (left_d: chisel3.domain.Type, right_d: chisel3.domain.Type) =>
// Pick the directional sense using the same rule as Records: if the
// left-hand side can't be a sink, flip so that the sink is writable.
val (sink, source) =
if (!MonoConnect.canBeSink(left_d, context_mod) && MonoConnect.canBeSink(right_d, context_mod)) {
(right_d, left_d)
} else {
(left_d, right_d)
}
try {
MonoConnect.domainDefine(sourceInfo, sink, source, context_mod)
} catch {
case MonoConnectException(message) => throw BiConnectException(message)
}
case (left_e: Element, right_e: Element) => {
elemConnect(sourceInfo, left_e, right_e, context_mod)
// TODO(twigg): Verify the element-level classes are connectable
Expand Down
27 changes: 26 additions & 1 deletion core/src/main/scala/chisel3/internal/MonoConnect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import chisel3._
import chisel3.experimental.{Analog, BaseModule, SourceInfo}
import chisel3.internal.binding._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl.ir.{Block, Connect, DefInvalid, ProbeDefine, PropAssign}
import chisel3.internal.firrtl.ir.{Block, Connect, DefInvalid, DomainDefine, ProbeDefine, PropAssign}
import chisel3.internal.firrtl.Converter
import chisel3.experimental.dataview.{isView, reify, reifyIdentityView}
import chisel3.properties.{Class, Property}
Expand Down Expand Up @@ -80,6 +80,10 @@ private[chisel3] object MonoConnect {
MonoConnectException(s"Source ${formatName(source)} of Probed type cannot participate in a mono connection (:=)")
def SinkProbeMonoConnectionException(sink: Data) =
MonoConnectException(s"Sink ${formatName(sink)} of Probed type cannot participate in a mono connection (:=)")
def MismatchedDomainException(sink: chisel3.domain.Type, source: chisel3.domain.Type) =
MonoConnectException(
s"Sink (${sink.domain.name}) and Source (${source.domain.name}) are different kinds of domains."
)

/** Check if the argument is visible from current block scope
*
Expand Down Expand Up @@ -155,6 +159,9 @@ private[chisel3] object MonoConnect {
elemConnect(sourceInfo, sink_e, source_e, context_mod)
case (sink_p: Property[_], source_p: Property[_]) =>
propConnect(sourceInfo, sink_p, source_p, context_mod)
// Two domains are connected at the root.
case (sink_d: chisel3.domain.Type, source_d: chisel3.domain.Type) =>
domainDefine(sourceInfo, sink_d, source_d, context_mod)

// Handle Vec case
case (sink_v: Vec[Data @unchecked], source_v: Vec[Data @unchecked]) =>
Expand Down Expand Up @@ -456,6 +463,24 @@ private[chisel3] object MonoConnect {
}
}

def domainDefine(
sourceInfo: SourceInfo,
sink: chisel3.domain.Type,
source: chisel3.domain.Type,
context: BaseModule
): Unit = {
implicit val info: SourceInfo = sourceInfo
if (sink.domain != source.domain) {
throw MismatchedDomainException(sink, source)
}
checkConnect.checkConnection(sourceInfo, sink, source, context)
context match {
case rm: RawModule =>
rm.addCommand(DomainDefine(sourceInfo, sink.lref, source.ref))
case _ => throwException("Internal Error! Domain connection can only occur within RawModule.")
}
}

def probeDefine(
sourceInfo: SourceInfo,
sinkProbe: Data,
Expand Down
29 changes: 26 additions & 3 deletions src/test/scala/chiselTests/DomainSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,23 +110,46 @@ class DomainSpec extends AnyFlatSpec with Matchers with FileCheck {

}

they should "be capable of being forwarded with the domain define operation" in {
they should "be capable of being forwarded with the domain define operation or connects" in {

class Foo extends RawModule {
val a = IO(Input(ClockDomain.Type()))
val b = IO(Output(ClockDomain.Type()))

domain.define(b, a)
b := a
b <> a
b :<= a
b :<>= a
}

ChiselStage.emitCHIRRTL(new Foo).fileCheck() {
"""|CHECK: module Foo :
|CHECK: domain_define b = a
"""|CHECK: module Foo :
|CHECK-COUNT-5: domain_define b = a
|CHECK-NOT: domain_define
|""".stripMargin
}

}

they should "error if connecting two different kinds of domains with :=" in {

object DomainA extends Domain
object DomainB extends Domain

class Foo extends RawModule {
val a = IO(Input(DomainA.Type()))
val b = IO(Output(DomainB.Type()))
b := a
}

val exception = intercept[ChiselException] {
ChiselStage.elaborate(new Foo, Array("--throw-on-first-error"))
}
exception.getMessage should include("are different kinds of domains")

}

behavior of "The associate method"

it should "error if given zero arguments" in {
Expand Down
Loading