8000 Fix Data.findFirstTypeMismatch to check all elements of Bundles (backport #3928) by mergify[bot] · Pull Request #3929 · chipsalliance/chisel · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix Data.findFirstTypeMismatch to check all elements of Bundles (backport #3928) #3929

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

Merged
merged 1 commit into from
Mar 12, 2024
Merged
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
8000
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/src/main/scala/chisel3/Data.scala
Original file line number Diff line number Diff line change
Expand Up @@ -579,14 +579,14 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
case (r1: Record, r2: Record) if !strictTypes || r1.getClass == r2.getClass =>
val (larger, smaller, msg) =
if (r1._elements.size >= r2._elements.size) (r1, r2, "Left") else (r2, r1, "Right")
larger._elements.collectFirst {
larger._elements.flatMap {
case (name, data) =>
val recurse = smaller._elements.get(name) match {
case None => Some(s": Dangling field on $msg")
case Some(data2) => rec(data, data2)
}
recurse.map("." + name + _)
}.flatten
}.headOption
case (v1: Vec[_], v2: Vec[_]) =>
if (v1.size != v2.size) {
Some(s": Left (size ${v1.size}) and Right (size ${v2.size}) have different lengths.")
Expand Down
102 changes: 102 additions & 0 deletions src/test/scala/chiselTests/reflect/CheckTypeEquivalenceSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: Apache-2.0

package chiselTests.reflect

import circt.stage.ChiselStage
import chisel3._
import chisel3.reflect.DataMirror
import chiselTests.ChiselFlatSpec
import org.scalactic.source.Position
import chisel3.experimental.Analog

object CheckTypeEquivalenceSpec {
private def test[A <: Data, B <: Data](gen1: A, gen2: B, expectSame: Boolean)(implicit pos: Position): Unit = {
class TestModule extends RawModule {
val foo = IO(Flipped(gen1))
val bar = IO(gen2)
if (expectSame) {
assert(DataMirror.checkTypeEquivalence(gen1, gen2), s"Unbound types $gen1 and $gen2 should be the same")
assert(DataMirror.checkTypeEquivalence(foo, bar), s"Bound values $foo and $bar should be the same")
} else {
assert(!DataMirror.checkTypeEquivalence(gen1, gen2), s"Unbound types $gen1 and $gen2 should NOT be the same")
assert(!DataMirror.checkTypeEquivalence(foo, bar), s"Bound values $foo and $bar NOT should be the same")
}
}
ChiselStage.emitCHIRRTL(new TestModule)
}
private def testSame[A <: Data, B <: Data](gen1: A, gen2: B)(implicit pos: Position): Unit = test(gen1, gen2, true)
private def testDiff[A <: Data, B <: Data](gen1: A, gen2: B)(implicit pos: Position): Unit = test(gen1, gen2, false)

private def elementTypes =
Seq(UInt(8.W), UInt(), SInt(8.W), SInt(), Bool(), Clock(), Reset(), AsyncReset(), Analog(8.W))
private def elementTypeCombinations = elementTypes.combinations(2).map { pair => (pair(0), pair(1)) }

// Use of 2 Data here is arbitrary, they aren't being compared
private class BoxBundle[A <: Data, B <: Data](gen1: A, gen2: B) extends Bundle {
val foo = gen1.cloneType
val bar = gen2.cloneType
}
}

class CheckTypeEquivalenceSpec extends ChiselFlatSpec {
import CheckTypeEquivalenceSpec._

behavior.of("DataMirror.checkTypeEquivalence")

it should "support equivalence of Element types" in {
for (tpe <- elementTypes) {
ADA1 testSame(tpe, tpe.cloneType)
}
}

it should "show non-equivalence of Element types" in {
for ((gen1, gen2) <- elementTypeCombinations) {
testDiff(gen1, gen2)
}
}

it should "support equivalence of Vecs" in {
// Shouldn't need to check many different sizes
for (size <- 0 to 2) {
for (eltTpe <- elementTypes) {
testSame(Vec(size, eltTpe), Vec(size, eltTpe))
}
}
}

it should "support non-equivalence of Vecs" in {
// Shouldn't need to check many different sizes
for (size <- 0 to 2) {
for (eltTpe <- elementTypes) {
testDiff(Vec(size, eltTpe), Vec(size + 1, eltTpe))
}
}
}

it should "support equivalence of Bundles" in {
for ((gen1, gen2) <- elementTypeCombinations) {
testSame(new BoxBundle(gen1, gen2), new BoxBundle(gen1, gen2))
}
}

it should "support non-equivalence of Bundles" in {
for ((gen1, gen2) <- elementTypeCombinations) {
// Note 2nd argument has arguments backwards
testDiff(new BoxBundle(gen1, gen2), new BoxBundle(gen2, gen1))
}
}

// Test for https://github.com/chipsalliance/chisel/issues/3922
it should "check all fields of a Bundle (not just first or last)" in {
class StartAndEndSameBundle(extraField: Boolean) extends Bundle {
val foo = UInt(8.W)
val mid = if (extraField) Some(UInt(8.W)) else None
val bar = UInt(8.W)
}
// Sanity checks
testSame(new StartAndEndSameBundle(true), new StartAndEndSameBundle(true))
testSame(new StartAndEndSameBundle(false), new StartAndEndSameBundle(false))
// Real check
testDiff(new StartAndEndSameBundle(true), new StartAndEndSameBundle(false))
}
}
0