From 45e235a5948a1cd15b8ccb5f437dc6f2ff80cb96 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 10 May 2017 12:09:59 -0700 Subject: 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.--- .../src/main/scala/chisel3/core/Aggregate.scala | 4 +- .../src/main/scala/chisel3/core/BiConnect.scala | 61 +++--- .../CompatibilityInteroperabilitySpec.scala | 221 +++++++++++++++++++++ 3 files changed, 261 insertions(+), 25 deletions(-) create mode 100644 src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala 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() + }) + } +} + -- cgit v1.2.3