summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Koenig2017-05-10 12:09:59 -0700
committerGitHub2017-05-10 12:09:59 -0700
commit45e235a5948a1cd15b8ccb5f437dc6f2ff80cb96 (patch)
treee21826d7f231b3553a0d9001cdf987beded4c1d4
parent9ad6c747ddcedb831dbfbcd970a46966f986b800 (diff)
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.
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala61
-rw-r--r--src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala221
3 files changed, 261 insertions, 25 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 6a4d8cff..3f81de9f 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -362,7 +362,7 @@ trait VecLike[T <: Data] extends collection.IndexedSeq[T] with HasId {
* Record should only be extended by libraries and fairly sophisticated generators.
* RTL writers should use [[Bundle]]. See [[Record#elements]] for an example.
*/
-abstract class Record extends Aggregate {
+abstract class Record(private[chisel3] implicit val compileOptions: CompileOptions) extends Aggregate {
/** The collection of [[Data]]
*
@@ -464,7 +464,7 @@ abstract class Record extends Aggregate {
* }
* }}}
*/
-class Bundle extends Record {
+class Bundle(implicit compileOptions: CompileOptions) extends Record {
override def className = "Bundle"
/** The collection of [[Data]]
diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
index 4240a945..0e5d4e8b 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
@@ -80,35 +80,50 @@ object BiConnect {
}
}
}
- // Handle Record case
- case (left_r: Record, right_r: Record) => {
- // Verify right has no extra fields that left doesn't have
- for((field, right_sub) <- right_r.elements) {
- if(!left_r.elements.isDefinedAt(field)) {
- if (connectCompileOptions.connectFieldsMustMatch) {
- throw MissingLeftFieldException(field)
- }
- }
+ // Handle Records defined in Chisel._ code (change to NotStrict)
+ case (left_r: Record, right_r: Record) => (left_r.compileOptions, right_r.compileOptions) match {
+ case (ExplicitCompileOptions.NotStrict, _) =>
+ left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ case (_, ExplicitCompileOptions.NotStrict) =>
+ left_r.bulkConnect(right_r)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ case _ => recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)
+ }
+
+ // Left and right are different subtypes of Data so fail
+ case (left, right) => throw MismatchedException(left.toString, right.toString)
+ }
+
+ // Do connection of two Records
+ def recordConnect(sourceInfo: SourceInfo,
+ connectCompileOptions: CompileOptions,
+ left_r: Record,
+ right_r: Record,
+ context_mod: UserModule): Unit = {
+ // Verify right has no extra fields that left doesn't have
+ for((field, right_sub) <- right_r.elements) {
+ if(!left_r.elements.isDefinedAt(field)) {
+ if (connectCompileOptions.connectFieldsMustMatch) {
+ throw MissingLeftFieldException(field)
}
- // For each field in left, descend with right
- for((field, left_sub) <- left_r.elements) {
- try {
- right_r.elements.get(field) match {
- case Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod)
- case None => {
- if (connectCompileOptions.connectFieldsMustMatch) {
- throw MissingRightFieldException(field)
- }
- }
+ }
+ }
+ // For each field in left, descend with right
+ for((field, left_sub) <- left_r.elements) {
+ try {
+ right_r.elements.get(field) match {
+ case Some(right_sub) => connect(sourceInfo, connectCompileOptions, left_sub, right_sub, context_mod)
+ case None => {
+ if (connectCompileOptions.connectFieldsMustMatch) {
+ throw MissingRightFieldException(field)
}
- } catch {
- case BiConnectException(message) => throw BiConnectException(s".$field$message")
}
}
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s".$field$message")
}
- // Left and right are different subtypes of Data so fail
- case (left, right) => throw MismatchedException(left.toString, right.toString)
}
+ }
+
// These functions (finally) issue the connection operation
// Issue with right as sink, left as source
diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
new file mode 100644
index 00000000..2baa6e48
--- /dev/null
+++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
@@ -0,0 +1,221 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import collection.immutable.ListMap
+
+// Keep Chisel._ separate from chisel3._ below
+object CompatibilityComponents {
+ import Chisel._
+ import Chisel3Components._
+
+ class ChiselBundle extends Bundle {
+ val a = UInt(width = 32)
+ val b = UInt(width = 32).flip
+ }
+ class ChiselRecord extends Record {
+ val elements = ListMap("a" -> UInt(width = 32), "b" -> UInt(width = 32).flip)
+ override def cloneType = (new ChiselRecord).asInstanceOf[this.type]
+ }
+
+ abstract class ChiselDriverModule(_io: => Record) extends Module {
+ val io = _io
+ io.elements("a").asUInt := UInt(123)
+ assert(io.elements("b").asUInt === UInt(123))
+ }
+ abstract class ChiselPassthroughModule(_io: => Record) extends Module {
+ val io = _io
+ io.elements("b").asUInt := io.elements("a").asUInt
+ }
+
+ class ChiselBundleModuleA extends ChiselDriverModule(new ChiselBundle)
+ class ChiselBundleModuleB extends ChiselPassthroughModule((new ChiselBundle).flip)
+ class ChiselRecordModuleA extends ChiselDriverModule(new ChiselRecord)
+ class ChiselRecordModuleB extends ChiselPassthroughModule((new ChiselRecord).flip)
+
+ class ChiselModuleChisel3BundleA extends ChiselDriverModule(new Chisel3Bundle)
+ class ChiselModuleChisel3BundleB extends ChiselPassthroughModule((new Chisel3Bundle).flip)
+ class ChiselModuleChisel3RecordA extends ChiselDriverModule(new Chisel3Record)
+ class ChiselModuleChisel3RecordB extends ChiselPassthroughModule((new Chisel3Record).flip)
+}
+
+object Chisel3Components {
+ import chisel3._
+ import CompatibilityComponents._
+
+ class Chisel3Bundle extends Bundle {
+ val a = Output(UInt(32.W))
+ val b = Input(UInt(32.W))
+ }
+
+ class Chisel3Record extends Record {
+ val elements = ListMap("a" -> Output(UInt(32.W)), "b" -> Input(UInt(32.W)))
+ override def cloneType = (new Chisel3Record).asInstanceOf[this.type]
+ }
+
+ abstract class Chisel3DriverModule(_io: => Record) extends Module {
+ val io = IO(_io)
+ io.elements("a").asUInt := 123.U
+ assert(io.elements("b").asUInt === 123.U)
+ }
+ abstract class Chisel3PassthroughModule(_io: => Record) extends Module {
+ val io = IO(_io)
+ io.elements("b").asUInt := io.elements("a").asUInt
+ }
+
+ class Chisel3BundleModuleA extends Chisel3DriverModule(new Chisel3Bundle)
+ class Chisel3BundleModuleB extends Chisel3PassthroughModule((new Chisel3Bundle).flip)
+ class Chisel3RecordModuleA extends Chisel3DriverModule(new Chisel3Record)
+ class Chisel3RecordModuleB extends Chisel3PassthroughModule((new Chisel3Record).flip)
+
+ class Chisel3ModuleChiselBundleA extends Chisel3DriverModule(new ChiselBundle)
+ class Chisel3ModuleChiselBundleB extends Chisel3PassthroughModule((new ChiselBundle).flip)
+ class Chisel3ModuleChiselRecordA extends Chisel3DriverModule(new ChiselRecord)
+ class Chisel3ModuleChiselRecordB extends Chisel3PassthroughModule((new ChiselRecord).flip)
+}
+
+class CompatibiltyInteroperabilitySpec extends ChiselFlatSpec {
+
+ "Modules defined in the Chisel._" should "successfully bulk connect in chisel3._" in {
+ import chisel3._
+ import chisel3.testers.BasicTester
+ import CompatibilityComponents._
+
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselBundleModuleA)
+ val b = Module(new ChiselBundleModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselRecordModuleA)
+ val b = Module(new ChiselRecordModuleB)
+ b.io <> a.io
+ stop()
+ })
+ }
+
+ "Moduless defined in the chisel3._" should "successfully bulk connect in Chisel._" in {
+ import Chisel._
+ import chisel3.testers.BasicTester
+ import Chisel3Components._
+
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3BundleModuleA)
+ val b = Module(new Chisel3BundleModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3RecordModuleA)
+ val b = Module(new Chisel3RecordModuleB)
+ b.io <> a.io
+ stop()
+ })
+ }
+
+
+ "Bundles defined in Chisel._" should "work in chisel3._ Modules" in {
+ import chisel3._
+ import chisel3.testers.BasicTester
+ import Chisel3Components._
+
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3ModuleChiselBundleA)
+ val b = Module(new Chisel3ModuleChiselBundleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3ModuleChiselRecordA)
+ val b = Module(new Chisel3ModuleChiselRecordB)
+ b.io <> a.io
+ stop()
+ })
+ }
+
+ "Bundles defined in chisel3._" should "work in Chisel._ Modules" in {
+ import chisel3._
+ import chisel3.testers.BasicTester
+ import CompatibilityComponents._
+
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselModuleChisel3BundleA)
+ val b = Module(new ChiselModuleChisel3BundleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselModuleChisel3RecordA)
+ val b = Module(new ChiselModuleChisel3RecordB)
+ b.io <> a.io
+ stop()
+ })
+ }
+
+
+ "Similar Bundles defined in the chisel3._ and Chisel._" should
+ "successfully bulk connect in chisel3._" in {
+ import chisel3._
+ import chisel3.testers.BasicTester
+ import Chisel3Components._
+ import CompatibilityComponents._
+
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselBundleModuleA)
+ val b = Module(new Chisel3BundleModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3BundleModuleA)
+ val b = Module(new ChiselBundleModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselRecordModuleA)
+ val b = Module(new Chisel3RecordModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3RecordModuleA)
+ val b = Module(new ChiselRecordModuleB)
+ b.io <> a.io
+ stop()
+ })
+ }
+ they should "successfully bulk connect in Chisel._" in {
+ import Chisel._
+ import chisel3.testers.BasicTester
+ import Chisel3Components._
+ import CompatibilityComponents._
+
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselBundleModuleA)
+ val b = Module(new Chisel3BundleModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3BundleModuleA)
+ val b = Module(new ChiselBundleModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new ChiselRecordModuleA)
+ val b = Module(new Chisel3RecordModuleB)
+ b.io <> a.io
+ stop()
+ })
+ assertTesterPasses(new BasicTester {
+ val a = Module(new Chisel3RecordModuleA)
+ val b = Module(new ChiselRecordModuleB)
+ b.io <> a.io
+ stop()
+ })
+ }
+}
+