Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More Unit Tests for Boring to Port Scenarios #4154

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
12 changes: 12 additions & 0 deletions src/main/scala/chisel3/util/experimental/BoringUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import chisel3.internal.{Builder, BuilderContextCache, NamedComponent, Namespace
import firrtl.transforms.{DontTouchAnnotation, NoDedupAnnotation}
import firrtl.passes.wiring.{SinkAnnotation, SourceAnnotation}
import firrtl.annotations.{ComponentName, ModuleName}
import chisel3.experimental.dataview.reifySingleData

/** An exception related to BoringUtils
* @param message the exception message
Expand Down Expand Up @@ -256,6 +257,17 @@ object BoringUtils {
def drill(source: A, path: Seq[BaseModule], connectionLocation: Seq[BaseModule], up: Boolean): A = {
path.zip(connectionLocation).foldLeft(source) {
case (rhs, (module, conLoc)) if (module.isFullyClosed) => boringError(module); DontCare.asInstanceOf[A]
case (rhs: Element, (module, _))
if ((up || isDriveDone(reifySingleData(rhs).get)) && module == path(0) && isPort(
reifySingleData(rhs).get
) &&
(!createProbe.nonEmpty || !createProbe.get.writable)) => {
// So far we can handle ports that are views of single elements only.
reifySingleData(rhs).get.asInstanceOf[A]
Comment on lines +260 to +266
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
case (rhs: Element, (module, _))
if ((up || isDriveDone(reifySingleData(rhs).get)) && module == path(0) && isPort(
reifySingleData(rhs).get
) &&
(!createProbe.nonEmpty || !createProbe.get.writable)) => {
// So far we can handle ports that are views of single elements only.
reifySingleData(rhs).get.asInstanceOf[A]
case (rhs: Element, (module, _))
if ((up || isDriveDone(reifySingleData(rhs).get)) && module == path(0) && isPort(
reify(rhs)
) &&
(!createProbe.nonEmpty || !createProbe.get.writable)) => {
// So far we can handle ports that are views of single elements only.
reify(rhs).asInstanceOf[A]

Since rhs is an Element you should be able to use reify which is Element => Element.

}
// TODO: What if rhs is a Property in a View?
// TODO: detect the case if we are a view but we need to collect from different locations.
// who makes the View / Wire in that case?
case (rhs, (module, _))
if ((up || isDriveDone(rhs)) && module == path(0) && isPort(rhs) &&
(!createProbe.nonEmpty || !createProbe.get.writable)) => {
Expand Down
159 changes: 158 additions & 1 deletion src/test/scala/chiselTests/BoringUtilsSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package chiselTests
import chisel3._
import chisel3.util.Counter
import chisel3.testers._
import chisel3.experimental.{BaseModule, ChiselAnnotation}
import chisel3.experimental.{BaseModule, ChiselAnnotation, ExtModule}
import chisel3.probe._
import chisel3.properties.Property
import chisel3.util.experimental.BoringUtils
Expand Down Expand Up @@ -377,6 +377,162 @@ class BoringUtilsSpec extends ChiselFlatSpec with ChiselRunners with Utils with
)()
}

it should "bore from an output Property on an ExtModule" in {
class BundleWithProperty extends Bundle {
val propVec = Vec(3, Property[Seq[Int]]())
}
class Baz extends ExtModule {
val a = IO(new BundleWithProperty)
}

class Foo extends RawModule {
val a = IO(Output(Property[Seq[Int]]()))

val baz = Module(new Baz)

a :#= BoringUtils.bore(baz.a.propVec.head)
}

val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Foo)
matchesAndOmits(chirrtl)(
)()
}

it should "bore from a Property for a FixedIOExtModule with an elemental property IO" in {
class Baz extends FixedIOExtModule[Property[Int]](Property[Int]())

class Foo extends RawModule {
val a = IO(Output(Property[Int]()))

val baz = Module(new Baz)

a :#= BoringUtils.bore(baz.io)
}

val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Foo, args = Array("--full-stacktrace"))
matchesAndOmits(chirrtl)(
"output io : Integer",
"propassign a, baz.io"
)()
}

it should "bore from a Property for a FixedIOExtModule with an elemental property IO through a layer of hierarchy" in {
class Baz extends FixedIOExtModule[Property[Int]](Property[Int]())
class Bar extends RawModule {
val baz = Module(new Baz)
}

class Foo extends RawModule {
val a = IO(Output(Property[Int]()))

val bar = Module(new Bar)

a :#= BoringUtils.bore(bar.baz.io)
}

val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Foo, args = Array("--full-stacktrace"))
matchesAndOmits(chirrtl)(
"output a_bore : Integer",
"propassign a_bore, baz.io",
"propassign a, bar.a_bore"
)()
}

it should "bore from a Property for a FixedIOExtModule with an aggregate with properties in it" in {
class BundleWithProperty extends Bundle {
val propVec = Vec(3, Property[Seq[Int]]())
}
class Baz extends FixedIOExtModule[BundleWithProperty](new BundleWithProperty)

class Foo extends RawModule {
val a = IO(Output(Property[Seq[Int]]()))

val baz = Module(new Baz)

a :#= BoringUtils.bore(baz.io.propVec.head)
}

val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Foo, args = Array("--full-stacktrace"))
matchesAndOmits(chirrtl)(
"output propVec : List<Integer>[3]",
"propassign a, baz.propVec[0]"
)()
}

it should "bore from a Data for a FixedIOExtModule with an aggregate with Data in it" in {
class BundleWithData extends Bundle {
val vec = Vec(3, Bool())
}
class Baz extends FixedIOExtModule[BundleWithData](new BundleWithData)

class Foo extends RawModule {
val a = IO(Output(Bool()))

val baz = Module(new Baz)

a :#= BoringUtils.bore(baz.io.vec.head)
}

val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Foo, args = Array("--full-stacktrace"))
matchesAndOmits(chirrtl)(
"output vec : UInt<1>[3]",
"wire a_bore : UInt<1>",
"connect a, a_bore",
"connect a_bore, baz.vec[0]"
)()
}

it should "bore from a Data for a Module with an aggregate with Data in it" in {
class BundleWithData extends Bundle {
val vec = Vec(3, Bool())
}
class Baz extends RawModule {
val io = IO(Output(new BundleWithData))
}

class Foo extends RawModule {
val a = IO(Output(Bool()))

val baz = Module(new Baz)

a :#= BoringUtils.bore(baz.io.vec.head)
}

val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Foo, args = Array("--full-stacktrace"))
matchesAndOmits(chirrtl)(
"output io : { vec : UInt<1>[3]}",
"wire a_bore : UInt<1>",
"connect a, a_bore",
"connect a_bore, baz.io.vec[0]"
)(
"output a_bore : UInt<1>"
)
}

it should "bore from a Data for a FixedIOModule with an aggregate with Data in it" in {
class BundleWithData extends Bundle {
val vec = Vec(3, Bool())
}
class Baz extends FixedIORawModule[BundleWithData](new BundleWithData)

class Foo extends RawModule {
val a = IO(Output(Bool()))

val baz = Module(new Baz)

a :#= BoringUtils.bore(baz.io.vec.head)
}

val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Foo, args = Array("--full-stacktrace"))
matchesAndOmits(chirrtl)(
"output vec : UInt<1>[3]",
"connect a, a_bore",
"connect a_bore, baz.vec[0]"
)(
"output a_bore : UInt<1>"
)
}

behavior.of("BoringUtils.drive")

it should "fail on probes" in {
Expand Down Expand Up @@ -486,4 +642,5 @@ class BoringUtilsSpec extends ChiselFlatSpec with ChiselRunners with Utils with
"propassign bar.bore, Integer(1)"
)()
}

}
Loading