diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/scala/chisel3/compatibility.scala | 1 | ||||
| -rw-r--r-- | src/main/scala/chisel3/package.scala | 1 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/BundleSpec.scala | 71 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/RecordSpec.scala | 119 |
4 files changed, 192 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index 613385af..abbe8ffe 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -36,6 +36,7 @@ package object Chisel { // scalastyle:ignore package.object.name val Vec = chisel3.core.Vec type Vec[T <: Data] = chisel3.core.Vec[T] type VecLike[T <: Data] = chisel3.core.VecLike[T] + type Record = chisel3.core.Record type Bundle = chisel3.core.Bundle val assert = chisel3.core.assert diff --git a/src/main/scala/chisel3/package.scala b/src/main/scala/chisel3/package.scala index 29095243..cba8dffe 100644 --- a/src/main/scala/chisel3/package.scala +++ b/src/main/scala/chisel3/package.scala @@ -26,6 +26,7 @@ package object chisel3 { // scalastyle:ignore package.object.name type Vec[T <: Data] = chisel3.core.Vec[T] type VecLike[T <: Data] = chisel3.core.VecLike[T] type Bundle = chisel3.core.Bundle + type Record = chisel3.core.Record val assert = chisel3.core.assert diff --git a/src/test/scala/chiselTests/BundleSpec.scala b/src/test/scala/chiselTests/BundleSpec.scala new file mode 100644 index 00000000..0a6866d3 --- /dev/null +++ b/src/test/scala/chiselTests/BundleSpec.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. + +package chiselTests + +import chisel3._ +import chisel3.testers.BasicTester + +trait BundleSpecUtils { + class BundleFooBar extends Bundle { + val foo = UInt(16.W) + val bar = UInt(16.W) + override def cloneType = (new BundleFooBar).asInstanceOf[this.type] + } + class BundleBarFoo extends Bundle { + val bar = UInt(16.W) + val foo = UInt(16.W) + override def cloneType = (new BundleBarFoo).asInstanceOf[this.type] + } + class BundleFoo extends Bundle { + val foo = UInt(16.W) + override def cloneType = (new BundleFoo).asInstanceOf[this.type] + } + class BundleBar extends Bundle { + val bar = UInt(16.W) + override def cloneType = (new BundleBar).asInstanceOf[this.type] + } + + class MyModule(output: Bundle, input: Bundle) extends Module { + val io = IO(new Bundle { + val in = Input(input) + val out = Output(output) + }) + io.out <> io.in + } + + class BundleSerializationTest extends BasicTester { + // Note that foo is higher order because its defined earlier in the Bundle + val bundle = Wire(new BundleFooBar) + bundle.foo := 0x1234.U + bundle.bar := 0x5678.U + // To UInt + val uint = bundle.asUInt + assert(uint.getWidth == 32) // elaboration time + assert(uint === "h12345678".asUInt(32.W)) + // Back to Bundle + val bundle2 = (new BundleFooBar).fromBits(uint) + assert(0x1234.U === bundle2.foo) + assert(0x5678.U === bundle2.bar) + stop() + } +} + +class BundleSpec extends ChiselFlatSpec with BundleSpecUtils { + "Bundles with the same fields but in different orders" should "bulk connect" in { + elaborate { new MyModule(new BundleFooBar, new BundleBarFoo) } + } + + "Bundles" should "follow UInt serialization/deserialization API" in { + assertTesterPasses { new BundleSerializationTest } + } + + "Bulk connect on Bundles" should "check that the fields match" in { + (the [ChiselException] thrownBy { + elaborate { new MyModule(new BundleFooBar, new BundleFoo) } + }).getMessage should include ("Right Record missing field") + + (the [ChiselException] thrownBy { + elaborate { new MyModule(new BundleFoo, new BundleFooBar) } + }).getMessage should include ("Left Record missing field") + } +} diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala new file mode 100644 index 00000000..c65693ed --- /dev/null +++ b/src/test/scala/chiselTests/RecordSpec.scala @@ -0,0 +1,119 @@ +// See LICENSE for license details. + +package chiselTests + +import chisel3._ +import chisel3.testers.BasicTester +import chisel3.util.{Counter, Queue} +import scala.collection.immutable.ListMap + +trait RecordSpecUtils { + // An example of how Record might be extended + // In this case, CustomBundle is a Record constructed from a Tuple of (String, Data) + // it is a possible implementation of a programmatic "Bundle" + // (and can by connected to MyBundle below) + final class CustomBundle(elts: (String, Data)*) extends Record { + val elements = ListMap(elts map { case (field, elt) => field -> elt.chiselCloneType }: _*) + def apply(elt: String): Data = elements(elt) + override def cloneType = (new CustomBundle(elements.toList: _*)).asInstanceOf[this.type] + } + class MyBundle extends Bundle { + val foo = UInt(32.W) + val bar = UInt(32.W) + override def cloneType = (new MyBundle).asInstanceOf[this.type] + } + // Useful for constructing types from CustomBundle + val fooBarType = new CustomBundle("foo" -> UInt(32.W), "bar" -> UInt(32.W)) + + class MyModule(output: => Record, input: => Record) extends Module { + val io = IO(new Bundle { + val in = Input(input) + val out = Output(output) + }) + io.out <> io.in + } + + class RecordSerializationTest extends BasicTester { + val recordType = new CustomBundle("fizz" -> UInt(16.W), "buzz" -> UInt(16.W)) + val record = Wire(recordType) + // Note that "buzz" was added later than "fizz" and is therefore higher order + record("fizz") := "hdead".U + record("buzz") := "hbeef".U + // To UInt + val uint = record.asUInt + assert(uint.getWidth == 32) // elaboration time + assert(uint === "hbeefdead".U) + // Back to Record + val record2 = recordType.fromBits(uint) + assert("hdead".U === record2("fizz").asUInt) + assert("hbeef".U === record2("buzz").asUInt) + stop() + } + + class RecordQueueTester extends BasicTester { + val queue = Module(new Queue(fooBarType, 4)) + queue.io.enq.valid := false.B + val (cycle, done) = Counter(true.B, 4) + + when (cycle === 0.U) { + queue.io.enq.bits("foo") := 1234.U + queue.io.enq.bits("bar") := 5678.U + queue.io.enq.valid := true.B + } + when (cycle === 1.U) { + queue.io.deq.ready := true.B + assert(queue.io.deq.valid === true.B) + assert(queue.io.deq.bits("foo").asUInt === 1234.U) + assert(queue.io.deq.bits("bar").asUInt === 5678.U) + } + when (done) { + stop() + } + } + + class RecordIOModule extends Module { + val io = IO(new CustomBundle("in" -> Input(UInt(32.W)), "out" -> Output(UInt(32.W)))) + io("out") := io("in") + } + + class RecordIOTester extends BasicTester { + val mod = Module(new RecordIOModule) + mod.io("in") := 1234.U + assert(mod.io("out").asUInt === 1234.U) + stop() + } +} + +class RecordSpec extends ChiselFlatSpec with RecordSpecUtils { + behavior of "Records" + + they should "bulk connect similarly to Bundles" in { + elaborate { new MyModule(fooBarType, fooBarType) } + } + + they should "bulk connect to Bundles" in { + elaborate { new MyModule(new MyBundle, fooBarType) } + } + + they should "follow UInt serialization/deserialization API" in { + assertTesterPasses { new RecordSerializationTest } + } + + they should "work as the type of a Queue" in { + assertTesterPasses { new RecordQueueTester } + } + + they should "work as the type of a Module's io" in { + assertTesterPasses { new RecordIOTester } + } + + "Bulk connect on Record" should "check that the fields match" in { + (the [ChiselException] thrownBy { + elaborate { new MyModule(fooBarType, new CustomBundle("bar" -> UInt(32.W))) } + }).getMessage should include ("Right Record missing field") + + (the [ChiselException] thrownBy { + elaborate { new MyModule(new CustomBundle("bar" -> UInt(32.W)), fooBarType) } + }).getMessage should include ("Left Record missing field") + } +} |
