Skip to content

Commit 45e235a

Browse files
authored
Add implicit CompileOptions to Record and Bundle (#595)
Fixes #495 Helps distinguish between Records/Bundles defined in Chisel._ vs. chisel3._. Also override compilationOptions when bulk connecting Records/Bundles defined in Chisel._. This allows Records/Bundles defined in Chisel._ code to be correctly bulk connected in chisel3._ code.
1 parent 9ad6c74 commit 45e235a

File tree

3 files changed

+261
-25
lines changed

3 files changed

+261
-25
lines changed

chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId {
362362
* Record should only be extended by libraries and fairly sophisticated generators.
363363
* RTL writers should use [[Bundle]]. See [[Record#elements]] for an example.
364364
*/
365-
abstract class Record extends Aggregate {
365+
abstract class Record(private[chisel3] implicit val compileOptions: CompileOptions) extends Aggregate {
366366

367367
/** The collection of [[Data]]
368368
*
@@ -464,7 +464,7 @@ abstract class Record extends Aggregate {
464464
* }
465465
* }}}
466466
*/
467-
class Bundle extends Record {
467+
class Bundle(implicit compileOptions: CompileOptions) extends Record {
468468
override def className = "Bundle"
469469

470470
/** The collection of [[Data]]

chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -80,35 +80,50 @@ object BiConnect {
8080
}
8181
}
8282
}
83-
// Handle Record case
84-
case (left_r: Record, right_r: Record) => {
85-
// Verify right has no extra fields that left doesn't have
86-
for((field, right_sub) <- right_r.elements) {
87-
if(!left_r.elements.isDefinedAt(field)) {
88-
if (connectCompileOptions.connectFieldsMustMatch) {
89-
throw MissingLeftFieldException(field)
90-
}
91-
}
83+
// Handle Records defined in Chisel._ code (change to NotStrict)
84+
case (left_r: Record, right_r: Record) => (left_r.compileOptions, right_r.compileOptions) match {
85+
case (ExplicitCompileOptions.NotStrict, _) =>
86+
left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
87+
case (_, ExplicitCompileOptions.NotStrict) =>
88+
left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
89+
case _ => recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)
90+
}
91+
92+
// Left and right are different subtypes of Data so fail
93+
case (left, right) => throw MismatchedException(left.toString, right.toString)
94+
}
95+
96+
// Do connection of two Records
97+
def recordConnect(sourceInfo: SourceInfo,
98+
connectCompileOptions: CompileOptions,
99+
left_r: Record,
100+
right_r: Record,
101+
context_mod: UserModule): Unit = {
102+
// Verify right has no extra fields that left doesn't have
103+
for((field, right_sub) <- right_r.elements) {
104+
if(!left_r.elements.isDefinedAt(field)) {
105+
if (connectCompileOptions.connectFieldsMustMatch) {
106+
throw MissingLeftFieldException(field)
92107
}
93-
// For each field in left, descend with right
94-
for((field, left_sub) <- left_r.elements) {
95-
try {
96-
right_r.elements.get(field) match {
97-
case Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod)
98-
case None => {
99-
if (connectCompileOptions.connectFieldsMustMatch) {
100-
throw MissingRightFieldException(field)
101-
}
102-
}
108+
}
109+
}
110+
// For each field in left, descend with right
111+
for((field, left_sub) <- left_r.elements) {
112+
try {
113+
right_r.elements.get(field) match {
114+
case Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod)
115+
case None => {
116+
if (connectCompileOptions.connectFieldsMustMatch) {
117+
throw MissingRightFieldException(field)
103118
}
104-
} catch {
105-
case BiConnectException(message) => throw BiConnectException(s".$field$message")
106119
}
107120
}
121+
} catch {
122+
case BiConnectException(message) => throw BiConnectException(s".$field$message")
108123
}
109-
// Left and right are different subtypes of Data so fail
110-
case (left, right) => throw MismatchedException(left.toString, right.toString)
111124
}
125+
}
126+
112127

113128
// These functions (finally) issue the connection operation
114129
// Issue with right as sink, left as source
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// See LICENSE for license details.
2+
3+
package chiselTests
4+
5+
import collection.immutable.ListMap
6+
7+
// Keep Chisel._ separate from chisel3._ below
8+
object CompatibilityComponents {
9+
import Chisel._
10+
import Chisel3Components._
11+
12+
class ChiselBundle extends Bundle {
13+
val a = UInt(width = 32)
14+
val b = UInt(width = 32).flip
15+
}
16+
class ChiselRecord extends Record {
17+
val elements = ListMap("a" -> UInt(width = 32), "b" -> UInt(width = 32).flip)
18+
override def cloneType = (new ChiselRecord).asInstanceOf[this.type]
19+
}
20+
21+
abstract class ChiselDriverModule(_io: => Record) extends Module {
22+
val io = _io
23+
io.elements("a").asUInt := UInt(123)
24+
assert(io.elements("b").asUInt === UInt(123))
25+
}
26+
abstract class ChiselPassthroughModule(_io: => Record) extends Module {
27+
val io = _io
28+
io.elements("b").asUInt := io.elements("a").asUInt
29+
}
30+
31+
class ChiselBundleModuleA extends ChiselDriverModule(new ChiselBundle)
32+
class ChiselBundleModuleB extends ChiselPassthroughModule((new ChiselBundle).flip)
33+
class ChiselRecordModuleA extends ChiselDriverModule(new ChiselRecord)
34+
class ChiselRecordModuleB extends ChiselPassthroughModule((new ChiselRecord).flip)
35+
36+
class ChiselModuleChisel3BundleA extends ChiselDriverModule(new Chisel3Bundle)
37+
class ChiselModuleChisel3BundleB extends ChiselPassthroughModule((new Chisel3Bundle).flip)
38+
class ChiselModuleChisel3RecordA extends ChiselDriverModule(new Chisel3Record)
39+
class ChiselModuleChisel3RecordB extends ChiselPassthroughModule((new Chisel3Record).flip)
40+
}
41+
42+
object Chisel3Components {
43+
import chisel3._
44+
import CompatibilityComponents._
45+
46+
class Chisel3Bundle extends Bundle {
47+
val a = Output(UInt(32.W))
48+
val b = Input(UInt(32.W))
49+
}
50+
51+
class Chisel3Record extends Record {
52+
val elements = ListMap("a" -> Output(UInt(32.W)), "b" -> Input(UInt(32.W)))
53+
override def cloneType = (new Chisel3Record).asInstanceOf[this.type]
54+
}
55+
56+
abstract class Chisel3DriverModule(_io: => Record) extends Module {
57+
val io = IO(_io)
58+
io.elements("a").asUInt := 123.U
59+
assert(io.elements("b").asUInt === 123.U)
60+
}
61+
abstract class Chisel3PassthroughModule(_io: => Record) extends Module {
62+
val io = IO(_io)
63+
io.elements("b").asUInt := io.elements("a").asUInt
64+
}
65+
66+
class Chisel3BundleModuleA extends Chisel3DriverModule(new Chisel3Bundle)
67+
class Chisel3BundleModuleB extends Chisel3PassthroughModule((new Chisel3Bundle).flip)
68+
class Chisel3RecordModuleA extends Chisel3DriverModule(new Chisel3Record)
69+
class Chisel3RecordModuleB extends Chisel3PassthroughModule((new Chisel3Record).flip)
70+
71+
class Chisel3ModuleChiselBundleA extends Chisel3DriverModule(new ChiselBundle)
72+
class Chisel3ModuleChiselBundleB extends Chisel3PassthroughModule((new ChiselBundle).flip)
73+
class Chisel3ModuleChiselRecordA extends Chisel3DriverModule(new ChiselRecord)
74+
class Chisel3ModuleChiselRecordB extends Chisel3PassthroughModule((new ChiselRecord).flip)
75+
}
76+
77+
class CompatibiltyInteroperabilitySpec extends ChiselFlatSpec {
78+
79+
"Modules defined in the Chisel._" should "successfully bulk connect in chisel3._" in {
80+
import chisel3._
81+
import chisel3.testers.BasicTester
82+
import CompatibilityComponents._
83+
84+
assertTesterPasses(new BasicTester {
85+
val a = Module(new ChiselBundleModuleA)
86+
val b = Module(new ChiselBundleModuleB)
87+
b.io <> a.io
88+
stop()
89+
})
90+
assertTesterPasses(new BasicTester {
91+
val a = Module(new ChiselRecordModuleA)
92+
val b = Module(new ChiselRecordModuleB)
93+
b.io <> a.io
94+
stop()
95+
})
96+
}
97+
98+
"Moduless defined in the chisel3._" should "successfully bulk connect in Chisel._" in {
99+
import Chisel._
100+
import chisel3.testers.BasicTester
101+
import Chisel3Components._
102+
103+
assertTesterPasses(new BasicTester {
104+
val a = Module(new Chisel3BundleModuleA)
105+
val b = Module(new Chisel3BundleModuleB)
106+
b.io <> a.io
107+
stop()
108+
})
109+
assertTesterPasses(new BasicTester {
110+
val a = Module(new Chisel3RecordModuleA)
111+
val b = Module(new Chisel3RecordModuleB)
112+
b.io <> a.io
113+
stop()
114+
})
115+
}
116+
117+
118+
"Bundles defined in Chisel._" should "work in chisel3._ Modules" in {
119+
import chisel3._
120+
import chisel3.testers.BasicTester
121+
import Chisel3Components._
122+
123+
assertTesterPasses(new BasicTester {
124+
val a = Module(new Chisel3ModuleChiselBundleA)
125+
val b = Module(new Chisel3ModuleChiselBundleB)
126+
b.io <> a.io
127+
stop()
128+
})
129+
assertTesterPasses(new BasicTester {
130+
val a = Module(new Chisel3ModuleChiselRecordA)
131+
val b = Module(new Chisel3ModuleChiselRecordB)
132+
b.io <> a.io
133+
stop()
134+
})
135+
}
136+
137+
"Bundles defined in chisel3._" should "work in Chisel._ Modules" in {
138+
import chisel3._
139+
import chisel3.testers.BasicTester
140+
import CompatibilityComponents._
141+
142+
assertTesterPasses(new BasicTester {
143+
val a = Module(new ChiselModuleChisel3BundleA)
144+
val b = Module(new ChiselModuleChisel3BundleB)
145+
b.io <> a.io
146+
stop()
147+
})
148+
assertTesterPasses(new BasicTester {
149+
val a = Module(new ChiselModuleChisel3RecordA)
150+
val b = Module(new ChiselModuleChisel3RecordB)
151+
b.io <> a.io
152+
stop()
153+
})
154+
}
155+
156+
157+
"Similar Bundles defined in the chisel3._ and Chisel._" should
158+
"successfully bulk connect in chisel3._" in {
159+
import chisel3._
160+
import chisel3.testers.BasicTester
161+
import Chisel3Components._
162+
import CompatibilityComponents._
163+
164+
assertTesterPasses(new BasicTester {
165+
val a = Module(new ChiselBundleModuleA)
166+
val b = Module(new Chisel3BundleModuleB)
167+
b.io <> a.io
168+
stop()
169+
})
170+
assertTesterPasses(new BasicTester {
171+
val a = Module(new Chisel3BundleModuleA)
172+
val b = Module(new ChiselBundleModuleB)
173+
b.io <> a.io
174+
stop()
175+
})
176+
assertTesterPasses(new BasicTester {
177+
val a = Module(new ChiselRecordModuleA)
178+
val b = Module(new Chisel3RecordModuleB)
179+
b.io <> a.io
180+
stop()
181+
})
182+
assertTesterPasses(new BasicTester {
183+
val a = Module(new Chisel3RecordModuleA)
184+
val b = Module(new ChiselRecordModuleB)
185+
b.io <> a.io
186+
stop()
187+
})
188+
}
189+
they should "successfully bulk connect in Chisel._" in {
190+
import Chisel._
191+
import chisel3.testers.BasicTester
192+
import Chisel3Components._
193+
import CompatibilityComponents._
194+
195+
assertTesterPasses(new BasicTester {
196+
val a = Module(new ChiselBundleModuleA)
197+
val b = Module(new Chisel3BundleModuleB)
198+
b.io <> a.io
199+
stop()
200+
})
201+
assertTesterPasses(new BasicTester {
202+
val a = Module(new Chisel3BundleModuleA)
203+
val b = Module(new ChiselBundleModuleB)
204+
b.io <> a.io
205+
stop()
206+
})
207+
assertTesterPasses(new BasicTester {
208+
val a = Module(new ChiselRecordModuleA)
209+
val b = Module(new Chisel3RecordModuleB)
210+
b.io <> a.io
211+
stop()
212+
})
213+
assertTesterPasses(new BasicTester {
214+
val a = Module(new Chisel3RecordModuleA)
215+
val b = Module(new ChiselRecordModuleB)
216+
b.io <> a.io
217+
stop()
218+
})
219+
}
220+
}
221+

0 commit comments

Comments
 (0)