1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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")
}
}
|