@@ -17,12 +17,116 @@ import firrtl.transforms.DontTouchAnnotation
1717import org .scalatest .flatspec .AnyFlatSpec
1818import org .scalatest .matchers .should .Matchers
1919
20+ abstract class ShouldntAssertTester (cyclesToWait : BigInt = 4 ) extends Module {
21+ val dut : BaseModule
22+ val (_, done) = Counter (true .B , 2 )
23+ when(done) { stop() }
24+ }
25+
2026class BoringUtilsSpec extends AnyFlatSpec with Matchers with LogUtils with FileCheck with ChiselSim {
2127 val args = Array (" --throw-on-first-error" , " --full-stacktrace" )
2228
29+ class BoringInverter extends Module {
30+ val io = IO (new Bundle {})
31+ val a = Wire (UInt (1 .W ))
32+ val notA = Wire (UInt (1 .W ))
33+ val b = Wire (UInt (1 .W ))
34+ a := 0 .U
35+ notA := ~ a
36+ b := a
37+ chisel3.assert(b === 1 .U )
38+ BoringUtils .addSource(notA, " x" )
39+ BoringUtils .addSink(b, " x" )
40+ }
41+
42+ behavior.of(" BoringUtils.addSink and BoringUtils.addSource" )
43+
44+ it should " connect two wires within a module" in {
45+ simulate(new ShouldntAssertTester { val dut = Module (new BoringInverter ) })(RunUntilFinished (3 ))
46+ }
47+
48+ trait WireX { this : BaseModule =>
49+ val x = dontTouch(Wire (UInt (4 .W )))
50+ }
51+
52+ class Source extends RawModule with WireX {
53+ val in = IO (Input (UInt ()))
54+ x := in
55+ }
56+
57+ class Sink extends RawModule with WireX {
58+ val out = IO (Output (UInt ()))
59+ x := 0 .U // Default value. Output is zero unless we bore...
60+ out := x
61+ }
62+
63+ class Top (val width : Int ) extends Module {
64+ /* From the perspective of deduplication, all sources are identical and all sinks are identical. */
65+ val sources = Seq .fill(3 )(Module (new Source ))
66+ val sinks = Seq .fill(6 )(Module (new Sink ))
67+
68+ /* Sources are differentiated by their input connections only. */
69+ sources.zip(Seq (0 , 1 , 2 )).map { case (a, b) => a.in := b.U }
70+
71+ /* Sinks are differentiated by their post-boring outputs. */
72+ sinks.zip(Seq (0 , 1 , 1 , 2 , 2 , 2 )).map { case (a, b) => chisel3.assert(a.out === b.U ) }
73+ }
74+
75+ /** This is testing a complicated wiring pattern and exercising
76+ * the necessity of disabling deduplication for sources and sinks.
77+ * Without disabling deduplication, this test will fail.
78+ */
79+ class TopTester extends ShouldntAssertTester {
80+ val dut = Module (new Top (4 ))
81+ BoringUtils .bore(dut.sources(1 ).x, Seq (dut.sinks(1 ).x, dut.sinks(2 ).x))
82+ BoringUtils .bore(dut.sources(2 ).x, Seq (dut.sinks(3 ).x, dut.sinks(4 ).x, dut.sinks(5 ).x))
83+ }
84+
85+ class TopTesterFail extends ShouldntAssertTester {
86+ val dut = Module (new Top (4 ))
87+ BoringUtils .addSource(dut.sources(1 ).x, " foo" , disableDedup = true )
88+ BoringUtils .addSink(dut.sinks(1 ).x, " foo" , disableDedup = true )
89+ BoringUtils .addSink(dut.sinks(2 ).x, " foo" , disableDedup = true )
90+
91+ BoringUtils .addSource(dut.sources(2 ).x, " bar" , disableDedup = true )
92+ BoringUtils .addSink(dut.sinks(3 ).x, " bar" , disableDedup = true )
93+ BoringUtils .addSink(dut.sinks(4 ).x, " bar" , disableDedup = true )
94+ BoringUtils .addSink(dut.sinks(5 ).x, " bar" , disableDedup = true )
95+ }
96+
2397 behavior.of(" BoringUtils.bore" )
2498
25- it should " pass a basic test" in {
99+ it should " connect across modules using BoringUtils.bore" in {
100+ simulate(new TopTester )(RunUntilFinished (3 ))
101+ }
102+
103+ // TODO: this test is not really testing anything as MFC does boring during
104+ // LowerAnnotations (which happens right after parsing). Consider reworking
105+ // this into a test that uses D/I (or some other mechanism of having a
106+ // pre-deduplicated circuit). This is likely better handled as a test in
107+ // CIRCT than in Chisel.
108+ it should " still work even with dedup off" in {
109+ simulate(new TopTesterFail )(RunUntilFinished (3 ))
110+ }
111+
112+ class InternalBore extends RawModule {
113+ val in = IO (Input (Bool ()))
114+ val out = IO (Output (Bool ()))
115+ out := false .B
116+ BoringUtils .bore(in, Seq (out))
117+ }
118+
119+ class InternalBoreTester extends ShouldntAssertTester {
120+ val dut = Module (new InternalBore )
121+ dut.in := true .B
122+ chisel3.assert(dut.out === true .B )
123+ }
124+
125+ it should " work for an internal, same module, BoringUtils.bore" in {
126+ simulate(new InternalBoreTester )(RunUntilFinished (3 ))
127+ }
128+
129+ it should " work using new API" in {
26130 class Baz extends RawModule {
27131 val a_wire = WireInit (UInt (1 .W ), DontCare )
28132 dontTouch(a_wire)
0 commit comments