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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
// SPDX-License-Identifier: Apache-2.0
package chiselTests
import chisel3._
import chisel3.util._
import chisel3.testers.{BasicTester, TesterDriver}
import chisel3.experimental._
/* This test is different from AnalogSpec in that it uses more complicated black boxes that can each
* drive the bidirectional bus. It was created to evaluate Analog with synthesis tools since the
* simple tests in AnalogSpec don't anything interesting in them to synthesize.
*/
class AnalogBlackBoxPort extends Bundle {
val in = Input(Valid(UInt(32.W)))
val out = Output(UInt(32.W))
}
// This IO can be used for a single BlackBox or to group multiple
// Has multiple ports for driving and checking but only one shared bus
class AnalogBlackBoxIO(val n: Int) extends Bundle {
require(n > 0)
val bus = Analog(32.W)
val port = Vec(n, new AnalogBlackBoxPort)
}
// Assigns bus to out
// Assigns in.bits + index to bus when in.valid
class AnalogBlackBox(index: Int) extends BlackBox(Map("index" -> index)) {
val io = IO(new AnalogBlackBoxIO(1))
}
// AnalogBlackBox wrapper, which extends Module to present the common io._ interface
class AnalogBlackBoxModule(index: Int) extends Module {
val io = IO(new AnalogBlackBoxIO(1))
val impl = Module(new AnalogBlackBox(index))
io <> impl.io
}
// Wraps up n blackboxes, connecing their buses and simply forwarding their ports up
class AnalogBlackBoxWrapper(n: Int, idxs: Seq[Int]) extends Module {
require(n > 0)
val io = IO(new AnalogBlackBoxIO(n))
val bbs = idxs.map(i => Module(new AnalogBlackBoxModule(i)))
io.bus <> bbs.head.io.bus // Always bulk connect io.bus to first bus
io.port <> bbs.flatMap(_.io.port) // Connect ports
attach(bbs.map(_.io.bus):_*) // Attach all the buses
}
// Common superclass for AnalogDUT and AnalogSmallDUT
abstract class AnalogDUTModule(numBlackBoxes: Int) extends Module {
require(numBlackBoxes > 0)
val io = IO(new Bundle {
val ports = Vec(numBlackBoxes, new AnalogBlackBoxPort)
})
}
/** Single test case for lots of things
*
* $ - Wire at top connecting child inouts (Done in AnalogDUT)
* $ - Port inout connected to 1 or more children inouts (AnalogBackBoxWrapper)
* $ - Multiple port inouts connected (AnalogConnector)
*/
class AnalogDUT extends AnalogDUTModule(5) { // 5 BlackBoxes
val mods = Seq(
Module(new AnalogBlackBoxWrapper(1, Seq(0))),
Module(new AnalogBlackBoxModule(1)),
Module(new AnalogBlackBoxWrapper(2, Seq(2, 3))), // 2 blackboxes
Module(new AnalogBlackBoxModule(4))
)
// Connect all ports to top
io.ports <> mods.flatMap(_.io.port)
// Attach first 3 Modules
attach(mods.take(3).map(_.io.bus):_*)
// Attach last module to 1st through AnalogConnector
val con = Module(new AnalogConnector)
attach(con.io.bus1, mods.head.io.bus)
attach(con.io.bus2, mods.last.io.bus)
}
/** Same as [[AnalogDUT]] except it omits [[AnalogConnector]] because that is currently not
* supported by Verilator
* @todo Delete once Verilator can handle [[AnalogDUT]]
*/
class AnalogSmallDUT extends AnalogDUTModule(4) { // 4 BlackBoxes
val mods = Seq(
Module(new AnalogBlackBoxWrapper(1, Seq(0))),
Module(new AnalogBlackBoxModule(1)),
Module(new AnalogBlackBoxWrapper(2, Seq(2, 3))) // 2 BlackBoxes
)
// Connect all ports to top
io.ports <> mods.flatMap(_.io.port)
// Attach first 3 Modules
attach(mods.take(3).map(_.io.bus):_*)
}
// This tester is primarily intended to be able to pass the dut to synthesis
class AnalogIntegrationTester(mod: => AnalogDUTModule) extends BasicTester {
val BusValue = 2.U(32.W) // arbitrary
val dut = Module(mod)
val expectedValue = Wire(UInt(32.W))
expectedValue := BusValue // Overridden each cycle
val (cycle, done) = Counter(true.B, dut.io.ports.size)
for ((dut, idx) <- dut.io.ports.zipWithIndex) {
printf(p"@$cycle: BlackBox #$idx: $dut\n")
// Defaults
dut.in.valid := false.B
dut.in.bits := BusValue
// Error checking
assert(dut.out === expectedValue)
when (cycle === idx.U) {
expectedValue := BusValue + idx.U
dut.in.valid := true.B
}
}
when (done) { stop() }
}
class AnalogIntegrationSpec extends ChiselFlatSpec {
behavior of "Verilator"
it should "support simple bidirectional wires" in {
assertTesterPasses(
new AnalogIntegrationTester(new AnalogSmallDUT),
Seq("/chisel3/AnalogBlackBox.v"),
TesterDriver.verilatorOnly
)
}
// Use this test once Verilator supports alias
ignore should "support arbitrary bidirectional wires" in {
assertTesterPasses(
new AnalogIntegrationTester(new AnalogDUT),
Seq("/chisel3/AnalogBlackBox.v"),
TesterDriver.verilatorOnly
)
}
}
|