summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/compatibility.scala1
-rw-r--r--src/main/scala/chisel3/package.scala1
-rw-r--r--src/test/scala/chiselTests/BundleSpec.scala71
-rw-r--r--src/test/scala/chiselTests/RecordSpec.scala119
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")
+ }
+}